package fuseau

  1. Overview
  2. Docs

Source file IO_unix.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
open struct
  let _default_buf_size = 16 * 1024
end

type file_descr = Unix.file_descr

let await_readable fd =
  let loop = U_loop.cur () in
  (* wait for FD to be ready *)
  Fuseau.Private_.suspend ~before_suspend:(fun ~wakeup ->
      ignore
        (loop#on_readable fd (fun ev ->
             wakeup ();
             Cancel_handle.cancel ev)
          : Cancel_handle.t))

let rec read fd buf i len : int =
  if len = 0 then
    0
  else (
    match Unix.read fd buf i len with
    | exception Unix.Unix_error ((Unix.EAGAIN | Unix.EWOULDBLOCK), _, _) ->
      await_readable fd;
      read fd buf i len
    | n -> n
  )

let await_writable fd =
  let loop = U_loop.cur () in
  (* wait for FD to be ready *)
  Fuseau.Private_.suspend ~before_suspend:(fun ~wakeup ->
      ignore
        (loop#on_writable fd (fun ev ->
             wakeup ();
             Cancel_handle.cancel ev)
          : Cancel_handle.t))

let rec write_once fd buf i len : int =
  if len = 0 then
    0
  else (
    match Unix.write fd buf i len with
    | exception Unix.Unix_error ((Unix.EAGAIN | Unix.EWOULDBLOCK), _, _) ->
      await_writable fd;
      write_once fd buf i len
    | n -> n
  )

let write fd buf i len : unit =
  let i = ref i in
  let len = ref len in
  while !len > 0 do
    let n = write_once fd buf !i !len in
    i := !i + n;
    len := !len - n
  done

module Out = struct
  include Iostream.Out

  let of_unix_fd ?(close_noerr = false) ?(buf = Bytes.create _default_buf_size)
      fd : t =
    let buf_off = ref 0 in

    let[@inline] is_full () = !buf_off = Bytes.length buf in

    let flush () =
      if !buf_off > 0 then (
        write fd buf 0 !buf_off;
        buf_off := 0
      )
    in

    object
      method output_char c =
        if is_full () then flush ();
        Bytes.set buf !buf_off c;
        incr buf_off

      method output bs i len : unit =
        let i = ref i in
        let len = ref len in

        while !len > 0 do
          (* make space *)
          if is_full () then flush ();

          let n = min !len (Bytes.length buf - !buf_off) in
          Bytes.blit bs !i buf !buf_off n;
          buf_off := !buf_off + n;
          i := !i + n;
          len := !len - n
        done;
        (* if full, write eagerly *)
        if is_full () then flush ()

      method close () =
        if close_noerr then (
          try
            flush ();
            Unix.close fd
          with _ -> ()
        ) else (
          flush ();
          Unix.close fd
        )

      method flush = flush
    end
end

module In = struct
  include Iostream.In

  let of_unix_fd ?(close_noerr = false) ?(buf = Bytes.create _default_buf_size)
      (fd : Unix.file_descr) : t =
    let buf_len = ref 0 in
    let buf_off = ref 0 in

    let refill () =
      buf_off := 0;
      buf_len := read fd buf 0 (Bytes.length buf)
    in

    object
      method input b i len : int =
        if !buf_len = 0 then refill ();
        let n = min len !buf_len in
        if n > 0 then (
          Bytes.blit buf !buf_off b i n;
          buf_off := !buf_off + n;
          buf_len := !buf_len - n
        );
        n

      method close () =
        if close_noerr then (
          try Unix.close fd with _ -> ()
        ) else
          Unix.close fd
    end
end
OCaml

Innovation. Community. Security.