345 lines
10 KiB
OCaml
345 lines
10 KiB
OCaml
(* Lightweight thread library for Objective Caml
|
|
* http://www.ocsigen.org/lwt
|
|
* Module Lwt_unix
|
|
* Copyright (C) 2010 Jérémie Dimino
|
|
* 2010 Pierre Chambart
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as
|
|
* published by the Free Software Foundation, with linking exceptions;
|
|
* either version 2.1 of the License, or (at your option) any later
|
|
* version. See COPYING file for details.
|
|
*
|
|
* This program 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
* 02111-1307, USA.
|
|
*)
|
|
|
|
#include "src/unix/lwt_config.ml"
|
|
|
|
open Bigarray
|
|
open Lwt
|
|
|
|
type t = (char, int8_unsigned_elt, c_layout) Array1.t
|
|
|
|
let create size = Array1.create char c_layout size
|
|
let length bytes = Array1.dim bytes
|
|
|
|
external get : t -> int -> char = "%caml_ba_ref_1"
|
|
external set : t -> int -> char -> unit = "%caml_ba_set_1"
|
|
|
|
external unsafe_get : t -> int -> char = "%caml_ba_unsafe_ref_1"
|
|
external unsafe_set : t -> int -> char -> unit = "%caml_ba_unsafe_set_1"
|
|
|
|
external unsafe_fill : t -> int -> int -> char -> unit = "lwt_unix_fill_bytes" "noalloc"
|
|
|
|
let fill bytes ofs len ch =
|
|
if ofs < 0 || len < 0 || ofs > length bytes - len then
|
|
invalid_arg "Lwt_bytes.fill"
|
|
else
|
|
unsafe_fill bytes ofs len ch
|
|
|
|
(* +-----------------------------------------------------------------+
|
|
| Blitting |
|
|
+-----------------------------------------------------------------+ *)
|
|
|
|
external unsafe_blit_string_bytes : string -> int -> t -> int -> int -> unit = "lwt_unix_blit_string_bytes" "noalloc"
|
|
external unsafe_blit_bytes_string : t -> int -> string -> int -> int -> unit = "lwt_unix_blit_bytes_string" "noalloc"
|
|
external unsafe_blit : t -> int -> t -> int -> int -> unit = "lwt_unix_blit_bytes_bytes" "noalloc"
|
|
|
|
let blit_string_bytes src_buf src_ofs dst_buf dst_ofs len =
|
|
if (len < 0
|
|
|| src_ofs < 0 || src_ofs > String.length src_buf - len
|
|
|| dst_ofs < 0 || dst_ofs > length dst_buf - len) then
|
|
invalid_arg "String.blit"
|
|
else
|
|
unsafe_blit_string_bytes src_buf src_ofs dst_buf dst_ofs len
|
|
|
|
let blit_bytes_string src_buf src_ofs dst_buf dst_ofs len =
|
|
if (len < 0
|
|
|| src_ofs < 0 || src_ofs > length src_buf - len
|
|
|| dst_ofs < 0 || dst_ofs > String.length dst_buf - len) then
|
|
invalid_arg "String.blit"
|
|
else
|
|
unsafe_blit_bytes_string src_buf src_ofs dst_buf dst_ofs len
|
|
|
|
let blit src_buf src_ofs dst_buf dst_ofs len =
|
|
if (len < 0
|
|
|| src_ofs < 0 || src_ofs > length src_buf - len
|
|
|| dst_ofs < 0 || dst_ofs > length dst_buf - len) then
|
|
invalid_arg "String.blit"
|
|
else
|
|
unsafe_blit src_buf src_ofs dst_buf dst_ofs len
|
|
|
|
let of_string str =
|
|
let len = String.length str in
|
|
let bytes = create len in
|
|
unsafe_blit_string_bytes str 0 bytes 0 len;
|
|
bytes
|
|
|
|
let to_string bytes =
|
|
let len = length bytes in
|
|
let str = String.create len in
|
|
unsafe_blit_bytes_string bytes 0 str 0 len;
|
|
str
|
|
|
|
let proxy = Array1.sub
|
|
|
|
let extract buf ofs len =
|
|
if ofs < 0 || len < 0 || ofs > length buf - len then
|
|
invalid_arg "Lwt_bytes.extract"
|
|
else begin
|
|
let buf' = create len in
|
|
blit buf ofs buf' 0 len;
|
|
buf'
|
|
end
|
|
|
|
let copy buf =
|
|
let len = length buf in
|
|
let buf' = create len in
|
|
blit buf 0 buf' 0 len;
|
|
buf'
|
|
|
|
(* +-----------------------------------------------------------------+
|
|
| IOs |
|
|
+-----------------------------------------------------------------+ *)
|
|
|
|
open Lwt_unix
|
|
|
|
external stub_read : Unix.file_descr -> t -> int -> int -> int = "lwt_unix_bytes_read"
|
|
external read_job : Unix.file_descr -> t -> int -> int -> [ `unix_bytes_read ] job = "lwt_unix_bytes_read_job"
|
|
external read_result : [ `unix_bytes_read ] job -> int = "lwt_unix_bytes_read_result"
|
|
external read_free : [ `unix_bytes_read ] job -> unit = "lwt_unix_bytes_read_free" "noalloc"
|
|
|
|
let read fd buf pos len =
|
|
if pos < 0 || len < 0 || pos > length buf - len then
|
|
invalid_arg "Lwt_bytes.read"
|
|
else
|
|
blocking fd >>= function
|
|
| true ->
|
|
lwt () = wait_read fd in
|
|
execute_job (read_job (unix_file_descr fd) buf pos len) read_result read_free
|
|
| false ->
|
|
wrap_syscall Read fd (fun () -> stub_read (unix_file_descr fd) buf pos len)
|
|
|
|
external stub_write : Unix.file_descr -> t -> int -> int -> int = "lwt_unix_bytes_write"
|
|
external write_job : Unix.file_descr -> t -> int -> int -> [ `unix_bytes_write ] job = "lwt_unix_bytes_write_job"
|
|
external write_result : [ `unix_bytes_write ] job -> int = "lwt_unix_bytes_write_result"
|
|
external write_free : [ `unix_bytes_write ] job -> unit = "lwt_unix_bytes_write_free" "noalloc"
|
|
|
|
let write fd buf pos len =
|
|
if pos < 0 || len < 0 || pos > length buf - len then
|
|
invalid_arg "Lwt_bytes.write"
|
|
else
|
|
blocking fd >>= function
|
|
| true ->
|
|
lwt () = wait_write fd in
|
|
execute_job (write_job (unix_file_descr fd) buf pos len) write_result write_free
|
|
| false ->
|
|
wrap_syscall Write fd (fun () -> stub_write (unix_file_descr fd) buf pos len)
|
|
|
|
#if windows
|
|
|
|
let recv fd buf pos len flags =
|
|
raise (Lwt_sys.Not_available "Lwt_bytes.recv")
|
|
|
|
#else
|
|
|
|
external stub_recv : Unix.file_descr -> t -> int -> int -> Unix.msg_flag list -> int = "lwt_unix_bytes_recv"
|
|
|
|
let recv fd buf pos len flags =
|
|
if pos < 0 || len < 0 || pos > length buf - len then
|
|
invalid_arg "recv"
|
|
else
|
|
wrap_syscall Read fd (fun () -> stub_recv (unix_file_descr fd) buf pos len flags)
|
|
|
|
#endif
|
|
|
|
#if windows
|
|
|
|
let send fd buf pos len flags =
|
|
raise (Lwt_sys.Not_available "Lwt_bytes.send")
|
|
|
|
#else
|
|
|
|
external stub_send : Unix.file_descr -> t -> int -> int -> Unix.msg_flag list -> int = "lwt_unix_bytes_send"
|
|
|
|
let send fd buf pos len flags =
|
|
if pos < 0 || len < 0 || pos > length buf - len then
|
|
invalid_arg "send"
|
|
else
|
|
wrap_syscall Write fd (fun () -> stub_send (unix_file_descr fd) buf pos len flags)
|
|
|
|
#endif
|
|
|
|
type io_vector = {
|
|
iov_buffer : t;
|
|
iov_offset : int;
|
|
iov_length : int;
|
|
}
|
|
|
|
let io_vector ~buffer ~offset ~length = {
|
|
iov_buffer = buffer;
|
|
iov_offset = offset;
|
|
iov_length = length;
|
|
}
|
|
|
|
let check_io_vectors func_name iovs =
|
|
List.iter
|
|
(fun iov ->
|
|
if iov.iov_offset < 0
|
|
|| iov.iov_length < 0
|
|
|| iov.iov_offset > length iov.iov_buffer - iov.iov_length then
|
|
invalid_arg func_name)
|
|
iovs
|
|
|
|
#if windows
|
|
|
|
let recv_msg ~socket ~io_vectors =
|
|
raise (Lwt_sys.Not_available "recv_msg")
|
|
|
|
#else
|
|
|
|
external stub_recv_msg : Unix.file_descr -> int -> io_vector list -> int * Unix.file_descr list = "lwt_unix_bytes_recv_msg"
|
|
|
|
let recv_msg ~socket ~io_vectors =
|
|
check_io_vectors "recv_msg" io_vectors;
|
|
let n_iovs = List.length io_vectors in
|
|
wrap_syscall Read socket
|
|
(fun () ->
|
|
stub_recv_msg (unix_file_descr socket) n_iovs io_vectors)
|
|
|
|
#endif
|
|
|
|
#if windows
|
|
|
|
let send_msg ~socket ~io_vectors ~fds =
|
|
raise (Lwt_sys.Not_available "send_msg")
|
|
|
|
#else
|
|
|
|
external stub_send_msg : Unix.file_descr -> int -> io_vector list -> int -> Unix.file_descr list -> int = "lwt_unix_bytes_send_msg"
|
|
|
|
let send_msg ~socket ~io_vectors ~fds =
|
|
check_io_vectors "send_msg" io_vectors;
|
|
let n_iovs = List.length io_vectors and n_fds = List.length fds in
|
|
wrap_syscall Write socket
|
|
(fun () ->
|
|
stub_send_msg (unix_file_descr socket) n_iovs io_vectors n_fds fds)
|
|
|
|
#endif
|
|
|
|
#if windows
|
|
|
|
let recvfrom fd buf pos len flags =
|
|
raise (Lwt_sys.Not_available "Lwt_bytes.recvfrom")
|
|
|
|
#else
|
|
|
|
external stub_recvfrom : Unix.file_descr -> t -> int -> int -> Unix.msg_flag list -> int * Unix.sockaddr = "lwt_unix_bytes_recvfrom"
|
|
|
|
let recvfrom fd buf pos len flags =
|
|
if pos < 0 || len < 0 || pos > length buf - len then
|
|
invalid_arg "Lwt_bytes.recvfrom"
|
|
else
|
|
wrap_syscall Read fd (fun () -> stub_recvfrom (unix_file_descr fd) buf pos len flags)
|
|
|
|
#endif
|
|
|
|
#if windows
|
|
|
|
let sendto fd buf pos len flags addr =
|
|
raise (Lwt_sys.Not_available "Lwt_bytes.sendto")
|
|
|
|
#else
|
|
|
|
external stub_sendto : Unix.file_descr -> t -> int -> int -> Unix.msg_flag list -> Unix.sockaddr -> int = "lwt_unix_bytes_sendto_byte" "lwt_unix_bytes_sendto"
|
|
|
|
let sendto fd buf pos len flags addr =
|
|
if pos < 0 || len < 0 || pos > length buf - len then
|
|
invalid_arg "Lwt_bytes.sendto"
|
|
else
|
|
wrap_syscall Write fd (fun () -> stub_sendto (unix_file_descr fd) buf pos len flags addr)
|
|
|
|
#endif
|
|
|
|
(* +-----------------------------------------------------------------+
|
|
| Memory mapped files |
|
|
+-----------------------------------------------------------------+ *)
|
|
|
|
let map_file ~fd ?pos ~shared ?(size=(-1)) () =
|
|
Array1.map_file fd ?pos char c_layout shared size
|
|
|
|
external mapped : t -> bool = "lwt_unix_mapped" "noalloc"
|
|
|
|
type advice =
|
|
| MADV_NORMAL
|
|
| MADV_RANDOM
|
|
| MADV_SEQUENTIAL
|
|
| MADV_WILLNEED
|
|
| MADV_DONTNEED
|
|
|
|
#if windows
|
|
|
|
let madvise buf pos len advice =
|
|
raise (Lwt_sys.Not_available "madvise")
|
|
|
|
#else
|
|
|
|
external stub_madvise : t -> int -> int -> advice -> unit = "lwt_unix_madvise"
|
|
|
|
let madvise buf pos len advice =
|
|
if pos < 0 || len < 0 || pos > length buf - len then
|
|
invalid_arg "Lwt_bytes.madvise"
|
|
else
|
|
stub_madvise buf pos len advice
|
|
|
|
#endif
|
|
|
|
external get_page_size : unit -> int = "lwt_unix_get_page_size"
|
|
|
|
let page_size = get_page_size ()
|
|
|
|
#if windows
|
|
|
|
let mincore buffer offset states =
|
|
raise (Lwt_sys.Not_available "mincore")
|
|
|
|
let wait_mincore buffer offset =
|
|
raise (Lwt_sys.Not_available "mincore")
|
|
|
|
#else
|
|
|
|
external stub_mincore : t -> int -> int -> bool array -> unit = "lwt_unix_mincore"
|
|
|
|
let mincore buffer offset states =
|
|
if (offset mod page_size <> 0
|
|
|| offset < 0
|
|
|| offset > length buffer - (Array.length states * page_size)) then
|
|
invalid_arg "Lwt_bytes.mincore"
|
|
else
|
|
stub_mincore buffer offset (Array.length states * page_size) states
|
|
|
|
external wait_mincore_job : t -> int -> [ `unix_wait_mincore ] job = "lwt_unix_wait_mincore_job"
|
|
external wait_mincore_free : [ `unix_wait_mincore ] job -> unit = "lwt_unix_wait_mincore_free" "noalloc"
|
|
|
|
let wait_mincore buffer offset =
|
|
if offset < 0 || offset >= length buffer then
|
|
invalid_arg "Lwt_bytes.wait_mincore"
|
|
else begin
|
|
let state = [|false|] in
|
|
mincore buffer (offset - (offset mod page_size)) state;
|
|
if state.(0) then
|
|
return ()
|
|
else
|
|
execute_job (wait_mincore_job buffer offset) ignore wait_mincore_free
|
|
end
|
|
|
|
#endif
|