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
|
/**************************************************************************/
/* */
/* OCaml */
/* */
/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
/* */
/* Copyright 1996 Institut National de Recherche en Informatique et */
/* en Automatique. */
/* */
/* All rights reserved. This file is distributed under the terms of */
/* the GNU Lesser General Public License version 2.1, with the */
/* special exception on linking described in the file LICENSE. */
/* */
/**************************************************************************/
#include <errno.h>
#include <string.h>
#include <caml/mlvalues.h>
#include <caml/memory.h>
#include <caml/signals.h>
#include "unixsupport.h"
#ifndef EAGAIN
#define EAGAIN (-1)
#endif
#ifndef EWOULDBLOCK
#define EWOULDBLOCK (-1)
#endif
CAMLprim value caml_unix_write(value fd, value buf, value vofs, value vlen)
{
CAMLparam1(buf);
long ofs, len, written;
int numbytes, ret;
char iobuf[UNIX_BUFFER_SIZE];
ofs = Long_val(vofs);
len = Long_val(vlen);
written = 0;
while (len > 0) {
numbytes = len > UNIX_BUFFER_SIZE ? UNIX_BUFFER_SIZE : len;
memmove (iobuf, &Byte(buf, ofs), numbytes);
caml_enter_blocking_section();
ret = write(Int_val(fd), iobuf, numbytes);
caml_leave_blocking_section();
if (ret == -1) {
if ((errno == EAGAIN || errno == EWOULDBLOCK) && written > 0) break;
caml_uerror("write", Nothing);
}
written += ret;
ofs += ret;
len -= ret;
}
CAMLreturn(Val_long(written));
}
/* When an error occurs after the first loop, caml_unix_write reports the
error and discards the number of already written characters.
In this case, it would be better to discard the error and return the
number of bytes written, since most likely, caml_unix_write will be call
again, and the error will be reproduced and this time will be reported.
This problem is avoided in caml_unix_single_write, which is faithful to the
Unix system call. */
CAMLprim value caml_unix_single_write(value fd, value buf, value vofs,
value vlen)
{
CAMLparam1(buf);
long ofs, len;
int numbytes, ret;
char iobuf[UNIX_BUFFER_SIZE];
ofs = Long_val(vofs);
len = Long_val(vlen);
ret = 0;
if (len > 0) {
numbytes = len > UNIX_BUFFER_SIZE ? UNIX_BUFFER_SIZE : len;
memmove (iobuf, &Byte(buf, ofs), numbytes);
caml_enter_blocking_section();
ret = write(Int_val(fd), iobuf, numbytes);
caml_leave_blocking_section();
if (ret == -1) caml_uerror("single_write", Nothing);
}
CAMLreturn(Val_int(ret));
}
|