Skip to content
This repository was archived by the owner on Oct 24, 2020. It is now read-only.

Commit 8302117

Browse files
authored
Merge pull request #5 from madroach/file_desc_io
Add file-descriptor I/O functions
2 parents 8aadb56 + 681afd7 commit 8302117

File tree

11 files changed

+387
-4
lines changed

11 files changed

+387
-4
lines changed

appveyor.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
install:
2+
- cd "%APPVEYOR_BUILD_FOLDER%"
3+
- appveyor_init.cmd
4+
environment:
5+
OCAMLTOP_INCLUDE_PATH: 'C:\projects\ocaml-bigstring\.opam\ocaml-system\lib\toplevel'
6+
OCAMLRUNPARAM: "bs=8M"
7+
build_script:
8+
- cd "%APPVEYOR_BUILD_FOLDER%"
9+
- opam init --no-setup --yes --compiler=ocaml-system https://github.com/madroach/opam-repository.git
10+
- opam pin --no-action --verbose stdlib-shims https://github.com/ocaml/stdlib-shims.git
11+
- opam pin --no-action --verbose dune https://github.com/madroach/dune.git
12+
- opam install --yes --verbose --jobs=1 alcotest
13+
- opam exec -- dune runtest

appveyor_init.cmd

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
REM Download and install OCaml and flexlink (unless it was already done).
2+
REM Prepare the environment variables,... to use it. OCaml is installed
3+
REM at %OCAMLROOT%
4+
REM
5+
REM If you are using Cygwin, install it in C:\cygwin first and then
6+
REM execute this script. Execute bash with the option "-l".
7+
8+
REM set OCAMLROOT=%PROGRAMFILES%/OCaml
9+
set OCAMLROOT=C:/PROGRA~1/OCaml
10+
11+
if not defined OCAML_BRANCH (set OCAML_BRANCH=4.09)
12+
set OCAMLURL=https://ci.appveyor.com/api/projects/madroach/ocaml-appveyor/artifacts/ocaml-4.09.0.zip
13+
14+
if not exist "%OCAMLROOT%/bin/ocaml.exe" (
15+
echo Downloading OCaml %OCAML_BRANCH% from "%OCAMLURL%"
16+
appveyor DownloadFile "%OCAMLURL%" -FileName "%temp%/ocaml.zip"
17+
REM Intall 7za using Chocolatey:
18+
choco install 7zip.commandline
19+
cd "%PROGRAMFILES%"
20+
7za x -y "%temp%/ocaml.zip"
21+
del %temp%\ocaml.zip
22+
)
23+
24+
REM Cygwin is always installed on AppVeyor. Its path must come
25+
REM before the one of Git but after those of MSCV and OCaml.
26+
set Path=C:\cygwin\bin;%Path%
27+
28+
call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64
29+
30+
set Path=%OCAMLROOT%\bin;%OCAMLROOT%\bin\flexdll;C:\opam\bin;%Path%
31+
set CAML_LD_LIBRARY_PATH=%OCAMLROOT%/lib/stublibs
32+
33+
set CYGWINBASH=C:\cygwin\bin\bash.exe
34+
35+
if exist %CYGWINBASH% (
36+
REM Make sure that "link" is the MSVC one and not the Cynwin one.
37+
echo VCPATH="`cygpath -u -p '%Path%'`" > C:\cygwin\tmp\msenv
38+
echo PATH="$VCPATH:$PATH" >> C:\cygwin\tmp\msenv
39+
%CYGWINBASH% -lc "tr -d '\\r' </tmp/msenv > ~/.msenv64"
40+
%CYGWINBASH% -lc "echo '. ~/.msenv64' >> ~/.bash_profile"
41+
REM Make OCAMLROOT available in Unix form:
42+
echo OCAMLROOT_WIN="`cygpath -w -s '%OCAMLROOT%'`" > C:\cygwin\tmp\env
43+
(echo OCAMLROOT="`cygpath -u \"$OCAMLROOT_WIN\"`") >>C:\cygwin\tmp\env
44+
echo export OCAMLROOT_WIN OCAMLROOT >>C:\cygwin\tmp\env
45+
%CYGWINBASH% -lc "tr -d '\\r' </tmp/env >> ~/.bash_profile"
46+
)
47+
48+
set <NUL /p=Ready to use OCaml & ocamlc -version

bigstring-unix.opam

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: "bigstring-unix"
33
version: "0.2"
44
authors: "Simon Cruanes <simon.cruanes.2007@m4x.org>"
55
maintainer: "Simon Cruanes <simon.cruanes.2007@m4x.org>"
6-
synopsis: "A set of utils for dealing with `bigarrays` of `char` and memory-mapping"
6+
synopsis: "I/O functions for bigstrings using file descriptors and memory-maps"
77
tags: [ "bigstring" "bigarray" ]
88
homepage: "https://github.com/c-cube/ocaml-bigstring/"
99
bug-reports: "https://github.com/c-cube/ocaml-bigstring/issues"
@@ -13,9 +13,11 @@ build: [
1313
[ "dune" "runtest" "-p" name "-j" jobs ] {with-test}
1414
]
1515
depends: [
16-
"dune" {>= "1.1"}
16+
"dune" {>= "1.2"}
1717
"base-bigarray"
1818
"base-unix"
1919
"ocaml" {>= "4.03.0"}
20+
"alcotest" {with-test}
21+
"bigstring" {with-test}
2022
]
2123

bigstring.opam

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@ build: [
1313
[ "dune" "runtest" "-p" name "-j" jobs ] {with-test}
1414
]
1515
depends: [
16-
"dune" {>= "1.0"}
16+
"dune" {>= "1.2"}
1717
"base-bigarray"
1818
"base-bytes"
1919
"ocaml" {>= "4.03.0"}
20+
"alcotest" {with-test}
21+
"bigstring-unix" {with-test}
2022
]
2123

dune-project

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
(lang dune 1.1)
1+
(lang dune 1.2)
22
(name bigstring)

src/bigstring_unix.ml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,29 @@
33

44
type t = (char, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t
55

6+
(** {2 I/O} *)
7+
8+
let get_bounds name ?(off=0) ?len t =
9+
let buffer_len = Bigarray.Array1.dim t in
10+
let len = match len with
11+
| Some len -> len
12+
| None -> buffer_len - off
13+
in
14+
if len < 0 || off < 0 || buffer_len - off < len
15+
then invalid_arg ("Bigstring_unix." ^ name)
16+
else (off, len)
17+
18+
external read_fd : Unix.file_descr -> t -> int -> int -> int = "ocaml_bigstring_unix_read"
19+
external write_fd : Unix.file_descr -> t -> int -> int -> int = "ocaml_bigstring_unix_write"
20+
21+
let read fd ?off ?len t =
22+
let off, len = get_bounds "read" ?off ?len t in
23+
read_fd fd t off len
24+
and write fd ?off ?len t =
25+
let off, len = get_bounds "write" ?off ?len t in
26+
write_fd fd t off len
27+
28+
629
(** {2 Memory-map} *)
730

831
let map_file_descr ?pos ?(shared=false) fd len =

src/bigstring_unix.mli

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@ type t = (char, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t
66
on [Bigstring].
77
@since 0.3 *)
88

9+
(** {2 I/O} *)
10+
11+
(** These I/O functions are missing from the Bigarray library.
12+
They release the runtime during I/O. *)
13+
14+
val read : Unix.file_descr -> ?off:int -> ?len:int -> t -> int
15+
val write : Unix.file_descr -> ?off:int -> ?len:int -> t -> int
16+
17+
918
(** {2 Memory-map} *)
1019

1120
val with_map_file :

src/bigstring_unix_stubs.c

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/*
2+
* Copyright (c) 2019, Christopher Zimmermann
3+
*
4+
* Permission to use, copy, modify, and/or distribute this software for any
5+
* purpose with or without fee is hereby granted, provided that the above
6+
* copyright notice and this permission notice appear in all copies.
7+
*
8+
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9+
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10+
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11+
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12+
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13+
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14+
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15+
*/
16+
17+
18+
#include <caml/mlvalues.h>
19+
#include <caml/bigarray.h>
20+
#include <caml/unixsupport.h>
21+
#include <caml/threads.h>
22+
23+
#ifndef Handle_val
24+
#include <unistd.h>
25+
#endif
26+
27+
CAMLprim value
28+
ocaml_bigstring_unix_read(value vfd, value vba, value voff, value vlen)
29+
{
30+
void *iobuf = ((char *)Caml_ba_data_val(vba)) + Unsigned_long_val(voff);
31+
#ifdef Handle_val
32+
unsigned len;
33+
int err;
34+
35+
if (Descr_kind_val(vfd) == KIND_SOCKET) {
36+
SOCKET s = Socket_val(vfd);
37+
caml_release_runtime_system();
38+
if ((err = recv(s, iobuf, Unsigned_int_val(vlen), 0)) == SOCKET_ERROR)
39+
err = WSAGetLastError();
40+
else {
41+
len = err;
42+
err = 0;
43+
}
44+
caml_acquire_runtime_system();
45+
} else {
46+
HANDLE h = Handle_val(vfd);
47+
caml_release_runtime_system();
48+
if (ReadFile(h, iobuf, Unsigned_int_val(vlen), &len, NULL))
49+
err = 0;
50+
else {
51+
check_error:
52+
switch (err = GetLastError()) {
53+
case ERROR_BROKEN_PIPE:
54+
/* This is no error, but just a closed pipe. */
55+
err = len = 0;
56+
break;
57+
case ERROR_MORE_DATA:
58+
#if 1
59+
do {
60+
char buf[1024];
61+
unsigned dummy_len;
62+
if (ReadFile(h, buf, sizeof(buf), &dummy_len, NULL))
63+
break;
64+
else
65+
goto check_error;
66+
} while (0);
67+
#else
68+
err = 0;
69+
#endif
70+
default:
71+
break;
72+
}
73+
}
74+
caml_acquire_runtime_system();
75+
}
76+
/* GetLastError() and WSAGetLastError() error numbers _are_ compatible,
77+
* although not documented this behaviour will hopefully never change. */
78+
if (err) {
79+
win32_maperr(err);
80+
uerror("Bigstringaf.read", Nothing);
81+
}
82+
else
83+
return Val_int(len);
84+
85+
#else
86+
ssize_t ret;
87+
88+
caml_release_runtime_system();
89+
ret = read(Int_val(vfd), iobuf, Unsigned_long_val(vlen));
90+
caml_acquire_runtime_system();
91+
if (ret < 0) uerror("Bigstringaf.read", Nothing);
92+
return Val_long(ret);
93+
#endif
94+
}
95+
96+
CAMLprim value
97+
ocaml_bigstring_unix_write(value vfd, value vba, value voff, value vlen)
98+
{
99+
char *iobuf = ((char *)Caml_ba_data_val(vba)) + Unsigned_long_val(voff);
100+
#ifdef Handle_val
101+
unsigned len;
102+
int err;
103+
104+
if (Descr_kind_val(vfd) == KIND_SOCKET) {
105+
SOCKET s = Socket_val(vfd);
106+
caml_release_runtime_system();
107+
if ((err = send(s, iobuf, Unsigned_int_val(vlen), 0)) == SOCKET_ERROR)
108+
err = WSAGetLastError();
109+
else {
110+
len = err;
111+
err = 0;
112+
}
113+
caml_acquire_runtime_system();
114+
} else {
115+
HANDLE h = Handle_val(vfd);
116+
caml_release_runtime_system();
117+
if (WriteFile(h, iobuf, Unsigned_int_val(vlen), &len, NULL))
118+
err = 0;
119+
else
120+
err = GetLastError();
121+
caml_acquire_runtime_system();
122+
}
123+
/* GetLastError() and WSAGetLastError() error numbers _are_ compatible,
124+
* although not documented this behaviour will hopefully never change. */
125+
if (err) {
126+
win32_maperr(err);
127+
uerror("Bigstringaf.write", Nothing);
128+
}
129+
return Val_long(len);
130+
131+
#else
132+
ssize_t ret;
133+
134+
caml_release_runtime_system();
135+
ret = write(Int_val(vfd), iobuf, Unsigned_long_val(vlen));
136+
caml_acquire_runtime_system();
137+
if (ret < 0) uerror("Bigstringaf.write", Nothing);
138+
return Val_long(ret);
139+
#endif
140+
}

src/dune

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,7 @@
1919
(public_name bigstring-unix)
2020
(modules Bigstring_compat Bigstring_unix)
2121
(flags :standard -warn-error -3) ; deprecation
22+
(c_names bigstring_unix_stubs)
23+
(c_flags (-Wall -Wextra -Wpedantic))
2224
(synopsis "Bigstrings from Unix memory mapping.")
2325
(libraries bigarray unix))

test/dune

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
(test
2+
(name test)
3+
(modules test)
4+
(flags :standard -thread)
5+
(libraries alcotest bigstring bigstring-unix threads)
6+
(action
7+
; This enables runtime checks for use-after-free and double-free.
8+
(setenv MALLOC_CHECK_ 3
9+
(setenv MALLOC_PERTURB_ 195
10+
(run %{test} --color=always -q)))
11+
)
12+
)

0 commit comments

Comments
 (0)