PreviousUpNext

15.4.1184  src/lib/std/src/psx/posix-io-64.pkg

## posix-io-64.pkg



# Package for POSIX 1003.1 primitive I/O operations
# Using 64-bit positions.



stipulate
    package host_unt      =  host_unt_guts
    package int           =  int_guts
    package file_position =  file_position_guts
    package ci            =  mythryl_callable_c_library_interface;              # mythryl_callable_c_library_interface  is from   src/lib/std/src/unsafe/mythryl-callable-c-library-interface.pkg
    #
    fun cfun  fun_name
        =
        ci::find_c_function { lib_name => "posix_io", fun_name };
        #
        # If this code is revived, it should be changed from using
        # find_c_function  to using  find_c_function'  -- for a model
        # see src/lib/std/src/psx/posix-io.pkg
        #                               -- 2012-04-24 CrT
herein

    package posix_io {
        #
                                                    # inline_t          is from   src/lib/core/init/built-in.pkg        
        splitpos = inline_t::Int2::extern
        joinpos  = inline_t::Int2::intern

        package fs = posix_file

        package om:  api 
                          enum open_mode = O_RDONLY | O_WRONLY | O_RDWR 
                        end = FS
        use OM

        type word = host_unt::word
        type s_int = host_int::int

        my ++ = host_unt::bitwise_or
        my & = host_unt::bitwise_and
        infix ++ &


        my  osval:  String -> Sy_Int =  cfun "osval";                                           # osval         def in    src/c/lib/posix-io/osval.c
        #
        w_osval = host_unt::from_int o osval

        fun fail (fct, msg)
            =
            raise exception DIE ("POSIX_IO." + fct + ": " + msg)

        type File_Descriptor = fs::File_Descriptor
        type pid = posix_process::pid

        my pipe' : Void -> (Sy_Int, Sy_Int) =   cfun "pipe";                                    # pipe          def in    src/c/lib/posix-io/pipe.c
        #
        fun pipe ()
            =
            {   my (ifd, ofd) = pipe' ()
                #
                { infd  => fs::fd ifd,
                  outfd => fs::fd ofd
                };
            };

        my dup'  : s_int -> s_int         =  cfun "dup";                                # dup           def in    src/c/lib/posix-io/dup.c
        #
        fun dup fd
            =
            fs::fd (dup' (fs::intOf fd));

        my dup2' : (Sy_Int, Sy_Int) -> Void  =  cfun "dup2";                            # dup2          def in    src/c/lib/posix-io/dup2.c
        #
        fun dup2 { old, new }
            =
            dup2'(fs::intOf old, fs::intOf new);

        my close' : s_int -> Void = cfun "close";
        fun close fd = close' (fs::intOf fd)

        my read'    : (Int, Int) -> vector_of_one_byte_unts::Vector                 =  cfun "read";                     # read          def in    src/c/lib/posix-io/read.c
        my readbuf' : (Int, rw_vector_of_one_byte_unts::Rw_Vector, Int, Int) -> Int =  cfun "readbuf";          # readbuf       def in    src/c/lib/posix-io/readbuf.c

        fun readArr (fd, asl) = let
            my (buf, i, len) = rw_vector_slice_of_one_byte_unts::base asl
        in
            readbuf' (fs::intOf fd, buf, len, i)
        end
        fun readVec (fd, count) = 
              if count < 0 then raise exception SIZE else read'(fs::intOf fd, count)

        my writevec' : (Int,    vector_of_one_byte_unts::Vector,    Int, Int) -> Int =   cfun "writebuf";                       # writebuf      def in   src/c/lib/posix-io/writebuf.c
        my writearr' : (Int, rw_vector_of_one_byte_unts::Rw_Vector, Int, Int) -> Int =   cfun "writebuf";                       # writebuf      def in   src/c/lib/posix-io/writebuf.c

        fun writeArr (fd, asl) = let
            my (buf, i, len) = rw_vector_slice_of_one_byte_unts::base asl
        in
            writearr' (fs::intOf fd, buf, len, i)
        end

        fun writeVec (fd, vsl) = let
            my (buf, i, len) = vector_slice_of_one_byte_unts::base vsl
        in
            writevec' (fs::intOf fd, buf, len, i)
        end

        enum whence = SEEK_SET | SEEK_CUR | SEEK_END
        seek_set = osval "SEEK_SET"
        seek_cur = osval "SEEK_CUR"
        seek_end = osval "SEEK_END"

        fun whToWord SEEK_SET = seek_set
          | whToWord SEEK_CUR = seek_cur
          | whToWord SEEK_END = seek_end

        fun whFromWord wh =
              if wh == seek_set then SEEK_SET
              else if wh == seek_cur then SEEK_CUR
              else if wh == seek_end then SEEK_END
              else fail ("whFromWord", "unknown whence "$(int::to_string wh))

        package fd {

            local package bf = bit_flags_g ()
            in
                use BF
            end

            cloexec = fromWord (w_osval "cloexec")
          }

        package o {

            local package bf = bit_flags_g ()
            in
                use BF
            end

            append   = fromWord (w_osval "append")
            dsync    = fromWord (w_osval "dsync")
            nonblock = fromWord (w_osval "nonblock")
            rsync    = fromWord (w_osval "rsync")
            sync     = fromWord (w_osval "sync")
          }

        my fcntl_d:    (Sy_Int, Sy_Int) -> Sy_Int           =  cfun "fcntl_d";                  # fcntl_d       def in    src/c/lib/posix-io/fcntl_d.c
        my fcntl_gfd:   Sy_int          -> Sy_Unt           =  cfun "fcntl_gfd";                # fcntl_gfd     def in    src/c/lib/posix-io/fcntl_gfd.c
        my fcntl_sfd:  (Sy_Int, Sy_Unt) -> Void             =  cfun "fcntl_sfd";                # fcntl_sfd     def in    src/c/lib/posix-io/fcntl_sfd.c
        my fcntl_gfl:   Sy_Int          -> (Sy_Unt, Sy_Unt) =  cfun "fcntl_gfl";                # fcntl_gfl     def in    src/c/lib/posix-io/fcntl_gfl.c
        my fcntl_sfl:  (Sy_Int, Sy_Unt) -> Void             =  cfun "fcntl_sfl";                # fcntl_sfl     def in    src/c/lib/posix-io/fcntl_sfl.c
        #
        fun dupfd { old, base } = fs::fd (fcntl_d (fs::intOf old, fs::intOf base))
        fun getfd fd = fd::fromWord (fcntl_gfd (fs::intOf fd))
        fun setfd (fd, fl) = fcntl_sfd (fs::intOf fd, fd::toWord fl)
        fun getfl fd = let
              my (status, omode) = fcntl_gfl (fs::intOf fd)
              in
                (o::fromWord status, fs::omodeFromWord omode)
              end
        fun setfl (fd, status) = fcntl_sfl (fs::intOf fd, o::toWord status)

        enum lock_type = F_RDLCK | F_WRLCK | F_UNLCK

        package FLock {

            enum flock = FLOCK of {
                 ltype:  lock_type,
                 whence:  whence,
                 start:  file_position::Int,
                 len:    file_position::Int,
                 pid:  Null_Or( pid )
               }

            fun flock fv = FLOCK fv
            fun ltype (FLOCK fv) = fv.ltype
            fun whence (FLOCK fv) = fv.whence
            fun start (FLOCK fv) = fv.start
            fun len (FLOCK fv) = fv.len
            fun pid (FLOCK fv) = fv.pid
          }

        type flock_rep = s_int *
                         s_int *
                         one_word_unt::word * one_word_unt::word *
                         one_word_unt::word * one_word_unt::word *
                         s_int

        my fcntl_l:  (Sy_Int, Sy_Int, Flock_Rep) -> flock_rep = cfun "fcntl_l_64";              # fcntl_l_64            def in    src/c/lib/posix-io/fcntl_l_64.c
        f_getlk = osval "F_GETLK"
        f_setlk = osval "F_SETLK"
        f_setlkw = osval "F_SETLKW"
        f_rdlck = osval "F_RDLCK"
        f_wrlck = osval "F_WRLCK"
        f_unlck = osval "F_UNLCK"

        fun flockToRep (FLock::FLOCK { ltype, whence, start, len, ... } ) = let
              fun ltypeOf F_RDLCK = f_rdlck
                | ltypeOf F_WRLCK = f_wrlck
                | ltypeOf F_UNLCK = f_unlck
              my (shi, slo) = splitpos start
              my (lhi, llo) = splitpos len
              in
                (ltypeOf ltype, whToWord whence, shi, slo, lhi, llo, 0)
              end
        fun flockFromRep (usepid, (ltype, whence, shi, slo, lhi, llo, pid)) = let
              fun ltypeOf ltype = 
                    if ltype == f_rdlck then F_RDLCK
                    else if ltype == f_wrlck then F_WRLCK
                    else if ltype == f_unlck then F_UNLCK
                    else fail ("flockFromRep", "unknown lock type "$(int::to_string ltype))
              in
                FLock::FLOCK { 
                  ltype = ltypeOf ltype,
                  whence = whFromWord whence,
                  start = joinpos (shi, slo),
                  len = joinpos (lhi, llo),
                  pid = if usepid then THE (posix_process::PID pid) else NULL
                }
              end

        fun getlk (fd, flock) =
              flockFromRep (TRUE, fcntl_l (fs::intOf fd, f_getlk, flockToRep flock))
        fun setlk (fd, flock) =
              flockFromRep (FALSE, fcntl_l (fs::intOf fd, f_setlk, flockToRep flock))
        fun setlkw (fd, flock) =
              flockFromRep (FALSE, fcntl_l (fs::intOf fd, f_setlkw, flockToRep flock))

        my lseek'
            :
            (Sy_Int, one_word_unt::Unt, one_word_unt::Unt,  Sy_Int) -> (one_word_unt::Unt, one_word_unt::Unt)
            =
            cfun "lseek_64"                                                                     # lseek_64      def in    src/c/lib/posix-io/lseek_64.c

        fun lseek (fd, offset, whence)
            =
            let my (ohi, olo) = splitpos offset
            in joinpos (lseek'(fs::intOf fd, ohi, olo, whToWord whence))
            end

        my fsync' : Sy_Int -> Void =   cfun "fsync";                                            # fsync         def in    src/c/lib/posix-io/fsync.c
        #
        fun fsync fd
            =
            fsync' (fs::intOf fd)



        # Making readers and writers...
        #   (code lifted from winix-data-file-io-driver-for-posix--premicrothread.pkg
        #    and              winix-text-file-io-driver-for-posix--premicrothread.pkg)

        fun announce s x y = (
              # print "Posix: "; print (s: String); print "\n"; 
              x y)

        bufferSzB = 4096

        fun isRegFile fd = fs::st::isReg (fs::fstat fd)

        fun posFns (closed, fd) =
            if isRegFile fd then
                let pos = REF (file_position::from_int 0)
                    fun getPos () = *pos
                    fun setPos p =
                        (if *closed then raise exception io::CLOSED_IO_STREAM 
                         pos := announce "lseek" lseek (fd, p, SEEK_SET))
                    fun endPos () =
                        (if *closed then raise exception io::CLOSED_IO_STREAM 
                         fs::st::size (announce "fstat" fs::fstat fd))
                    fun verifyPos () =
                        let curPos = lseek (fd, file_position::from_int 0, SEEK_CUR)
                        in
                            pos := curPos; curPos
                        end
                in
                    ignore (verifyPos ());
                    { pos = pos,
                      getPos = THE getPos,
                      setPos = THE setPos,
                      endPos = THE endPos,
                      verifyPos = THE verifyPos }
                end
            else { pos = REF (file_position::from_int 0),
                   getPos = NULL, setPos = NULL, endPos = NULL, verifyPos = NULL }

        fun mkReader { mkRD, cvtVec, cvtArrSlice } { fd, name, initablekMode } =
            let closed = REF FALSE
                my { pos, getPos, setPos, endPos, verifyPos } = posFns (closed, fd)
                blocking = REF initablekMode
                fun blockingOn () = (setfl (fd, o::flags[]); blocking := TRUE)
                fun blockingOff () = (setfl (fd, o::nonblock); blocking := FALSE)
                fun incPos k = pos := position.+(*pos, file_position::from_int k)
                fun r_readVec n =
                    let v = announce "read" readVec (fd, n)
                    in
                        incPos (vector_of_one_byte_unts::length v);
                        cvtVec v
                    end
                fun r_readArr arg =
                    let k = announce "readBuf" readArr (fd, cvtArrSlice arg)
                    in
                        incPos k; k
                    end
                fun blockWrap f x =
                    (if *closed then raise exception io::CLOSED_IO_STREAM 
                     if *blocking then () else blockingOn();
                     f x)
                fun noBlockWrap f x =
                    (if *closed then raise exception io::CLOSED_IO_STREAM 
                     if *blocking then blockingOff() 
                     (/* try */ THE (f x)
                                except (e as assembly::RUNTIME_EXCEPTION(_, THE cause)) =>
                                       if cause == posix_error::again then NULL
                                       else raise exception e
                      /* end try */))
                fun r_close () =
                    if *closed then ()
                    else (closed:=TRUE; announce "close" close fd)
                isReg = isRegFile fd
                fun avail () =
                    if *closed then THE 0
                    else if isReg then
                        THE (file_position::toInt (fs::st::size (fs::fstat fd) - *pos))
                    else NULL
            in
                mkRD { name = name,
                       chunkSize = bufferSzB,
                       readVec = THE (blockWrap r_readVec),
                       readArr = THE (blockWrap r_readArr),
                       readVecNB = THE (noBlockWrap r_readVec),
                       readArrNB = THE (noBlockWrap r_readArr),
                       block = NULL,
                       can_readx = NULL,
                       avail = avail,
                       getPos = getPos,
                       setPos = setPos,
                       endPos = endPos,
                       verifyPos = verifyPos,
                       close = r_close,
                       ioDesc = THE (fs::fdToIOD fd) }
            end

        fun mkWriter { mkWR, cvtVecSlice, cvtArrSlice }
                     { fd, name, initablekMode, appendMode, chunkSize } =
            let closed = REF FALSE
                my { pos, getPos, setPos, endPos, verifyPos } = posFns (closed, fd)
                fun incPos k = (pos := position.+(*pos, file_position::from_int k); k)
                blocking = REF initablekMode
                appendFS = o::flags (if appendMode then [o::append] else NIL)
                fun updateStatus() =
                    let flgs = if *blocking then appendFS
                                   else o::flags[o::nonblock, appendFS]
                    in
                        announce "setfl" setfl (fd, flgs)
                    end
              fun ensureOpen () = if *closed then raise exception io::CLOSED_IO_STREAM else ()
              fun ensureBlock (x) =
                  if *blocking == x then () else (blocking := x; updateStatus())
              fun writeVec' (fd, s) = writeVec (fd, cvtVecSlice s)
              fun writeArr' (fd, s) = writeArr (fd, cvtArrSlice s)
              fun putV x = incPos (announce "writeVec" writeVec' x)
              fun putA x = incPos (announce "writeArr" writeArr' x)
              fun write (put, block) arg =
                  (ensureOpen();
                   ensureBlock block; 
                   put (fd, arg))
              fun handleBlock writer arg =
                  THE (writer arg)
                  except (e as assembly::RUNTIME_EXCEPTION(_, THE cause)) => 
                         if cause == posix_error::again then NULL else raise exception e
              fun w_close () =
                  if *closed then ()
                  else (closed:=TRUE; announce "close" close fd)
            in
                mkWR { name = name,
                       chunkSize = chunkSize,
                       writeVec = THE (write (putV, TRUE)),
                       writeArr = THE (write (putA, TRUE)),
                       writeVecNB = THE (handleBlock (write (putV, FALSE))),
                       writeArrNB = THE (handleBlock (write (putA, FALSE))),
                       block = NULL,
                       canOutput = NULL,
                       getPos = getPos,
                       setPos = setPos,
                       endPos = endPos,
                       verifyPos = verifyPos,
                       ioDesc = THE (fs::fdToIOD fd),
                       close = w_close }
            end

        local
            fun c2w_vs cvs = let
                my (cv, s, l) = vector_slice_of_chars::base cvs
                wv = byte::string_to_bytes cv
            in
                vector_slice_of_one_byte_unts::slice (wv, s, THE l)
            end

            # hack!!!  This only works because rw_vector_of_chars::Rw_Vector and
            #          rw_vector_of_one_byte_unts::Rw_Vector are really the same internally.
            my c2w_a
               :
               rw_vector_of_chars::Rw_Vector -> rw_vector_of_one_byte_unts::Rw_Vector
               =
               inline_t::cast

            fun c2w_as cas = let
                my (ca, s, l) = rw_vector_slice_of_chars::base cas
                wa = c2w_a ca
            in
                rw_vector_slice_of_one_byte_unts::slice (wa, s, THE l)
            end
        in

        mkBinReader = mkReader { mkRD = winix_base_data_file_io_driver_for_posix__premicrothread::RD,
                                     cvtVec = \\ v => v,
                                     cvtArrSlice = \\ s => s }

        mkTextReader = mkReader { mkRD = winix_base_text_file_io_driver_for_posix__premicrothread::RD,
                                      cvtVec = byte::bytes_to_string,
                                      cvtArrSlice =     c2w_as }

        mkBinWriter = mkWriter { mkWR = winix_base_data_file_io_driver_for_posix__premicrothread::WR,
                                     cvtVecSlice = \\ s => s,
                                     cvtArrSlice = \\ s => s }

        mkTextWriter = mkWriter { mkWR = winix_base_text_file_io_driver_for_posix__premicrothread::WR,
                                      cvtVecSlice =     c2w_vs,
                                      cvtArrSlice = c2w_as }

        end #  local 

    }; #  package posix_io 
end


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext