Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Out_channel.{is,set}_buffered to control buffering of output channels #10538

Merged
merged 20 commits into from
Sep 15, 2021
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions Changes
Expand Up @@ -45,6 +45,11 @@ Working version
(Nicolás Ojeda Bär, review by Daniel Bünzli, Simon Cruanes, Gabriel Scherer,
Guillaume Munch-Maccagnoni, Alain Frisch and Xavier Leroy)

- #10538: add Out_channel.set_buffered and Out_channel.is_buffered to control
the buffering mode of output channels.
(Nicolás Ojeda Bär, review by John Whitington, Daniel Bünzli, David Allsopp
and Xavier Leroy)

### Other libraries:

- #10192: Add support for Unix domain sockets on Windows and use them
Expand Down
3 changes: 3 additions & 0 deletions runtime/caml/io.h
Expand Up @@ -52,6 +52,7 @@ enum {
CHANNEL_FLAG_FROM_SOCKET = 1, /* For Windows */
CHANNEL_FLAG_MANAGED_BY_GC = 4, /* Free and close using GC finalization */
CHANNEL_TEXT_MODE = 8, /* "Text mode" for Windows and Cygwin */
CHANNEL_FLAG_UNBUFFERED = 16 /* Unbuffered (for output channels only) */
};

/* For an output channel:
Expand Down Expand Up @@ -109,6 +110,8 @@ CAMLextern struct channel * caml_all_opened_channels;
if (caml_channel_mutex_unlock != NULL) (*caml_channel_mutex_unlock)(channel)
#define Unlock_exn() \
if (caml_channel_mutex_unlock_exn != NULL) (*caml_channel_mutex_unlock_exn)()
#define Flush_if_unbuffered(channel) \
if (channel->flags & CHANNEL_FLAG_UNBUFFERED) caml_flush(channel)

/* Conversion between file_offset and int64_t */

Expand Down
1 change: 1 addition & 0 deletions runtime/extern.c
Expand Up @@ -899,6 +899,7 @@ void caml_output_val(struct channel *chan, value v, value flags)
caml_stat_free(blk);
blk = nextblk;
}
Flush_if_unbuffered(chan);
}

CAMLprim value caml_output_value(value vchan, value v, value flags)
Expand Down
21 changes: 21 additions & 0 deletions runtime/io.c
Expand Up @@ -669,13 +669,32 @@ CAMLprim value caml_ml_flush(value vchannel)
CAMLreturn (Val_unit);
}

CAMLprim value caml_ml_set_buffered(value vchannel, value mode)
{
struct channel * channel = Channel(vchannel);
if (Bool_val(mode)) {
channel->flags &= ~CHANNEL_FLAG_UNBUFFERED;
} else {
channel->flags |= CHANNEL_FLAG_UNBUFFERED;
caml_ml_flush(vchannel);
}
return Val_unit;
}

CAMLprim value caml_ml_is_buffered(value vchannel)
{
struct channel * channel = Channel(vchannel);
return Val_bool((channel->flags & CHANNEL_FLAG_UNBUFFERED) == 0);
nojb marked this conversation as resolved.
Show resolved Hide resolved
}

CAMLprim value caml_ml_output_char(value vchannel, value ch)
{
CAMLparam2 (vchannel, ch);
struct channel * channel = Channel(vchannel);

Lock(channel);
Putch(channel, Long_val(ch));
Flush_if_unbuffered(channel);
Unlock(channel);
CAMLreturn (Val_unit);
}
Expand All @@ -687,6 +706,7 @@ CAMLprim value caml_ml_output_int(value vchannel, value w)

Lock(channel);
caml_putword(channel, (uint32_t) Long_val(w));
Flush_if_unbuffered(channel);
Unlock(channel);
CAMLreturn (Val_unit);
}
Expand All @@ -707,6 +727,7 @@ CAMLprim value caml_ml_output_bytes(value vchannel, value buff, value start,
pos += written;
len -= written;
}
Flush_if_unbuffered(channel);
Unlock(channel);
CAMLreturn (Val_unit);
}
Expand Down
4 changes: 4 additions & 0 deletions stdlib/out_channel.ml
Expand Up @@ -45,3 +45,7 @@ let output_bytes = Stdlib.output_bytes
let output = Stdlib.output
let output_substring = Stdlib.output_substring
let set_binary_mode = Stdlib.set_binary_mode_out

external set_buffered : t -> bool -> unit = "caml_ml_set_buffered"

external is_buffered : t -> bool = "caml_ml_is_buffered"
16 changes: 16 additions & 0 deletions stdlib/out_channel.mli
Expand Up @@ -129,3 +129,19 @@ val set_binary_mode : t -> bool -> unit

This function has no effect under operating systems that do not distinguish
between text mode and binary mode. *)

val set_buffered : t -> bool -> unit
(** [set_buffered oc true] sets the channel [oc] to {e buffered} mode. In this
mode, data output on [oc] will be buffered until either the internal buffer
is full or the function {!flush} or {!flush_all} is called, at which point
it will be sent to the output device.

[set_buffered oc false] sets the channel [oc] to {e unbuffered} mode. In
this mode, data output on [oc] will be sent to the output device
immediately.

All channels are open in {e buffered} mode by default. *)

val is_buffered : t -> bool
(** [is_buffered oc] returns whether the channel [oc] is buffered (see
{!set_buffered}). *)