···11+type buf = (char, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t
22+33+type iovec
44+type t = iovec * buf array
55+external alloc_iovec : buf array -> iovec = "ocaml_uring_alloc_iovecs"
66+external free_iovec : iovec -> unit = "ocaml_uring_free_iovecs"
77+88+let alloc_buf len =
99+ Bigarray.(Array1.create char c_layout len)
1010+1111+let alloc bufs : t =
1212+ let v = alloc_iovec bufs in
1313+ v, bufs
1414+1515+let free (iov,_) = free_iovec iov
1616+1717+let nr_vecs (_,bufs) = Array.length bufs
1818+1919+let bufs t = snd t
2020+2121+let empty = alloc [||]
+10
iovec.mli
···11+type buf = (char, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t
22+type iovec
33+type t
44+55+val alloc : buf array -> t
66+val alloc_buf : int -> buf
77+val free : t -> unit
88+val nr_vecs : t -> int
99+val bufs : t -> buf array
1010+val empty : t
+6-5
urcat.ml
···99(* TODO make this work with ST_ISBLK *)
10101111let get_completion_and_print uring =
1212- let bufs, len = Uring.wait_cqe uring in
1212+ let iov, len = Uring.wait uring in
1313+ let bufs = Uring.Iovec.bufs iov in
1314 let remaining = ref len in
1415 Printf.eprintf "%d bytes read\n%!" len;
1516 Array.iter (fun buf ->
···2930 let fd = Unix.(handle_unix_error (openfile fname [O_RDONLY]) 0) in
3031 let file_sz = get_file_size fd in
3132 let blocks = if file_sz mod block_size <> 0 then (file_sz / block_size)+1 else file_sz/block_size in
3232- let bufs = Array.init blocks (fun _ -> Uring.iobuf_alloc block_size) in
3333- Uring.submit_readv uring fd bufs;
3333+ let bufs = Array.init blocks (fun _ -> Uring.Iovec.alloc_buf block_size) in
3434+ let iov = Uring.Iovec.alloc bufs in
3535+ Uring.submit_readv uring fd iov (iov :> Uring.Iovec.t);
3436 let numreq = Uring.submit uring in
3537 assert(numreq=1);
3638 ()
37393840let () =
3941 let fname = Sys.argv.(1) in
4040- let uring = Uring.create ~queue_depth:1 () in
4242+ let uring = Uring.create ~queue_depth:1 ~default:Uring.Iovec.empty () in
4143 submit_read_request fname uring;
4244 get_completion_and_print uring
4343-
+38-32
uring.ml
···11+module Iovec = Iovec
22+13type uring
22-33-type iobuf = (char, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t
44-55-let iobuf_alloc len = Bigarray.(Array1.create char c_layout len)
66-77-(** [ring_setup i] allocates a new io_uring with queue depth [i].
88- @raise [Failure] *)
94external uring_create : int -> uring = "ocaml_uring_setup"
105external uring_exit : uring -> unit = "ocaml_uring_exit"
116(* external uring_register_bigarray : uring -> iobuf -> unit = "ocaml_uring_register_ba" *)
127external uring_submit : uring -> int = "ocaml_uring_submit"
1381414-type iovecs
1515-external uring_alloc_iovecs : iobuf array -> iovecs = "ocaml_uring_alloc_iovecs"
1616-external uring_free_iovecs : iovecs -> unit = "ocaml_uring_free_iovecs"
99+type id = int
1010+external uring_submit_readv : uring -> Unix.file_descr -> id -> Iovec.t -> int64 -> unit = "ocaml_uring_submit_readv"
1111+external uring_submit_writev : uring -> Unix.file_descr -> id -> Iovec.t -> int64 -> unit = "ocaml_uring_submit_writev"
17121818-external uring_submit_readv : uring -> Unix.file_descr -> iovecs -> int -> unit = "ocaml_uring_submit_readv"
1919-external uring_wait_cqe : uring -> iovecs * int = "ocaml_uring_wait_cqe"
1313+external uring_wait_cqe : uring -> id * int = "ocaml_uring_wait_cqe"
20142121-type t = {
1515+type 'a t = {
2216 uring: uring;
2323- iobuf: iobuf;
2424- pending: (iovecs, iobuf array) Hashtbl.t;
1717+ iobuf: Iovec.buf;
1818+ mutable id_freelist: int list;
1919+ user_data: 'a array;
2520}
26212722let default_iobuf_len = 1024 * 1024 (* 1MB *)
28232929-let create ~queue_depth () =
2424+let create ~queue_depth ~default () =
3025 let uring = uring_create queue_depth in
3126 (* TODO posix memalign this to page *)
3232- let iobuf = Bigarray.(Array1.create char c_layout default_iobuf_len) in
2727+ let iobuf = Iovec.alloc_buf default_iobuf_len in
3328 (* uring_register_bigarray uring iobuf; *)
3429 Gc.finalise uring_exit uring;
3535- let pending = Hashtbl.create 1 in
3636- { uring; iobuf; pending }
3030+ let id_freelist = List.init queue_depth (fun i -> i) in
3131+ let user_data = Array.init queue_depth (fun _ -> default) in
3232+ { uring; iobuf; id_freelist; user_data }
37333838-let submit_readv {uring;pending;_} fd bufs =
3939- let len = Array.length bufs in
4040- let iovs = uring_alloc_iovecs bufs in
4141- uring_submit_readv uring fd iovs len;
4242- Hashtbl.add pending iovs bufs;
4343- ()
3434+let get_id t =
3535+ match t.id_freelist with
3636+ | [] -> raise Not_found
3737+ | hd::tl -> t.id_freelist <- tl; hd
3838+3939+let put_id t v =
4040+ t.id_freelist <- v :: t.id_freelist
4141+4242+let submit_readv t fd iovec user_data =
4343+ let id = get_id t in
4444+ uring_submit_readv t.uring fd id iovec 0L;
4545+ t.user_data.(id) <- user_data
4646+4747+let submit_writev t fd iovec user_data =
4848+ let id = get_id t in
4949+ uring_submit_writev t.uring fd id iovec 0L;
5050+ t.user_data.(id) <- user_data
44514552let submit {uring;_} =
4653 uring_submit uring
47544848-let wait_cqe {uring;pending;_} =
4949- let iovecs, len = uring_wait_cqe uring in
5050- let bas = Hashtbl.find pending iovecs in
5151- uring_free_iovecs iovecs;
5252- bas, len
5353-5555+let wait t =
5656+ let id, res = uring_wait_cqe t.uring in
5757+ let data = t.user_data.(id) in
5858+ put_id t id;
5959+ data, res
54605561(*
5662external ring_queue_write_full : t -> Unix.file_descr -> (Bigstringaf.t -> int -> unit) -> Bigstringaf.t -> int -> unit = "ring_queue_write_full"
···6066external ring_submit : t -> int = "ring_submit"
6167external ring_exit : t -> unit = "ring_exit"
6268external ring_wait : t -> unit = "ring_wait"
6363-*) 6969+*)
+9-7
uring.mli
···11+module Iovec = Iovec
1222-type t
33-type iobuf = (char, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t
33+type 'a t
4455-val iobuf_alloc : int -> iobuf
66-val create : queue_depth:int -> unit -> t
77-val submit_readv : t -> Unix.file_descr -> iobuf array -> unit
88-val submit : t -> int
99-val wait_cqe : t -> iobuf array * int55+val create : queue_depth:int -> default:'a -> unit -> 'a t
66+77+val submit_readv : 'a t -> Unix.file_descr -> Iovec.t -> 'a -> unit
88+val submit_writev : 'a t -> Unix.file_descr -> Iovec.t -> 'a -> unit
99+val submit : 'a t -> int
1010+1111+val wait : 'a t -> 'a * int
+28-10
uring_stubs.c
···6161value ocaml_uring_register_ba(value v_uring, value v_ba) {
6262 CAMLparam2(v_uring, v_ba);
6363 struct io_uring *ring = Ring_val(v_uring);
6464+ // TODO broken needs malloc
6465 struct iovec iov[1];
6566 iov[0].iov_base = Caml_ba_data_val(v_ba);
6667 iov[0].iov_len = Caml_ba_array_val(v_ba)->dim[0];
···105106}
106107107108value
108108-ocaml_uring_submit_readv(value v_uring, value v_fd, value iovecs, value v_len) {
109109+ocaml_uring_submit_readv(value v_uring, value v_fd, value v_id, value v_iov, value v_off) {
109110 CAMLparam1(v_uring);
110111 struct io_uring *ring = Ring_val(v_uring);
111111- struct iovec *iovs = (struct iovec *) (iovecs & ~1);
112112+ struct iovec *iovs = (struct iovec *) (Field(v_iov, 0) & ~1);
113113+ int len = Wosize_val(Field(v_iov, 1));
112114 struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
113115 if (!sqe)
114116 caml_failwith("unable to allocate SQE");
115115- io_uring_prep_readv(sqe, Int_val(v_fd), iovs, Int_val(v_len), 0);
116116- io_uring_sqe_set_data(sqe, iovs);
117117+ fprintf(stderr, "submit_readv: %d ents off %lu\n", len, Int64_val(v_off));
118118+ io_uring_prep_readv(sqe, Int_val(v_fd), iovs, len, Int64_val(v_off)); /* TODO add offset to intf */
119119+ io_uring_sqe_set_data(sqe, (void *)(uintptr_t)Int_val(v_id)); /* TODO sort out cast */
120120+ CAMLreturn(Val_unit);
121121+}
122122+123123+value
124124+ocaml_uring_submit_writev(value v_uring, value v_fd, value v_id, value v_iov, value v_off) {
125125+ CAMLparam1(v_uring);
126126+ struct io_uring *ring = Ring_val(v_uring);
127127+ struct iovec *iovs = (struct iovec *) (Field(v_iov, 0) & ~1);
128128+ int len = Wosize_val(Field(v_iov, 1));
129129+ struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
130130+ if (!sqe)
131131+ caml_failwith("unable to allocate SQE");
132132+ fprintf(stderr, "submit_writev: %d ents off %lu\n", len, Int64_val(v_off));
133133+ io_uring_prep_writev(sqe, Int_val(v_fd), iovs, len, Int64_val(v_off)); /* TODO add offset to intf */
134134+ io_uring_sqe_set_data(sqe, (void *)(uintptr_t)Int_val(v_id)); /* TODO sort out cast */
117135 CAMLreturn(Val_unit);
118136}
119137···129147{
130148 CAMLparam1(v_uring);
131149 CAMLlocal1(v_ret);
150150+ long id;
132151 struct io_uring *ring = Ring_val(v_uring);
133152 struct io_uring_cqe *cqe;
134153 fprintf(stderr, "cqe: waiting\n");
135154 io_uring_wait_cqe(ring, &cqe);
136136- fprintf(stderr, "cqe: %p res = %d\n", cqe, cqe->res);
137155 if (cqe->res < 0)
138156 caml_failwith(strerror(-cqe->res));
139139- fprintf(stderr, "ceq %p: res=%d\n", cqe, cqe->res);
140140- struct iovec *iovs = io_uring_cqe_get_data(cqe);
157157+ fprintf(stderr, "cqe %p: res=%d\n", cqe, cqe->res);
158158+ id = (long)io_uring_cqe_get_data(cqe);
141159 io_uring_cqe_seen(ring, cqe);
142142- v_ret = caml_alloc(3, 0);
143143- Store_field(v_ret, 0, (value)iovs | 1);
160160+ v_ret = caml_alloc(2, 0);
161161+ Store_field(v_ret, 0, Val_int(id));
144162 Store_field(v_ret, 1, Val_int(cqe->res));
145163 CAMLreturn(v_ret);
146164}
···338356 CAMLreturn(Val_int(submitted));
339357}
340358341341-#endif359359+#endif
+8-6
uring_test.ml
···11let () =
22- let t = Uring.create ~queue_depth:1 () in
22+ let t = Uring.create ~queue_depth:1 ~default:() () in
33 let fd = Unix.(handle_unix_error (openfile "test.txt" [O_RDONLY]) 0) in
44- let b1 = Uring.iobuf_alloc 3 in
55- let b2 = Uring.iobuf_alloc 5 in
66- Uring.submit_readv t fd [|b1;b2|];
44+ let b1 = Uring.Iovec.alloc_buf 3 in
55+ let b2 = Uring.Iovec.alloc_buf 7 in
66+ let iov = Uring.Iovec.alloc [|b1;b2|] in
77+ Uring.submit_readv t fd iov ();
78 let res = Uring.submit t in
89 Printf.eprintf "submitted %d\n%!" res;
99- let _,res = Uring.wait_cqe t in
1010+ let (), res = Uring.wait t in
1111+ Uring.Iovec.free iov;
1012 Printf.eprintf "res %d\n%!" res;
1113 Printf.eprintf "%s -- %s\n%!" (Bigstringaf.to_string b1) (Bigstringaf.to_string b2);
1214 ()
···4951 Printf.printf "Go connection!\n%!";
5052 client_fd := Some(new_client_fd);
5153 server_loop ()
5252- *)5454+ *)