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

Improve documentation of Unix.{in,out}_channel_of_descr #10181

Merged
merged 3 commits into from Jan 31, 2021
Merged
Changes from 1 commit
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
77 changes: 56 additions & 21 deletions otherlibs/unix/unix.mli
Expand Up @@ -394,16 +394,29 @@ val in_channel_of_descr : file_descr -> in_channel
Text mode is supported only if the descriptor refers to a file
or pipe, but is not supported if it refers to a socket.

On Windows: [set_binary_mode_in] always fails on channels created
with this function.

Beware that channels are buffered so more characters may have been
read from the file descriptor than those accessed using channel functions.
Channels also keep a copy of the current position in the file.
On Windows: {!Stdlib.set_binary_mode_in} always fails on channels
created with this function.

Beware that input channels are buffered, so more characters may
have been read from the descriptor than those accessed using
channel functions. Channels also keep a copy of the current
position in the file.

Closing the channel [ic] returned by [in_channel_of_descr fd]
using [close_in ic] also closes the underlying descriptor [fd].
Closing both the channel [ic] and the descriptor [fd] is
incorrect and will result in a {!Stdlib.Sys_error} or {!Unix.error}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, this is an undefined behavior, since the file descriptor may be reused in between. We cannot guarantee thet there is an exception raised here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All right, I just put "It is incorrect to close both the channel [ic] and the descriptor [fd].". Sometimes the less you write the better.

exception.

You need to explicitly close all channels created with this function.
Closing the channel also closes the underlying file descriptor (unless
it was already closed). *)
If several channels are created on the same descriptor, one of the
channels must be closed, but not the others.
Consider for example a descriptor [s] connected to a socket and two
channels [ic = in_channel_of_descr s] and [oc = out_channel_of_descr s].
The recommended closing protocol is to perform [close_out oc],
which flushes buffered output to the socket then closes the socket.
The [ic] channel must not be closed and will be collected by the GC
eventually.
*)

val out_channel_of_descr : file_descr -> out_channel
(** Create an output channel writing on the given descriptor.
Expand All @@ -412,17 +425,23 @@ val out_channel_of_descr : file_descr -> out_channel
Text mode is supported only if the descriptor refers to a file
or pipe, but is not supported if it refers to a socket.

On Windows: [set_binary_mode_out] always fails on channels created
On Windows: {!Stdlib.set_binary_mode_out} always fails on channels created
with this function.

Beware that channels are buffered so you may have to [flush] them
to ensure that all data has been sent to the file descriptor.
Channels also keep a copy of the current position in the file.
Beware that output channels are buffered, so you may have to call
{!Stdlib.flush} to ensure that all data has been sent to the
descriptor. Channels also keep a copy of the current position in
the file.

You need to explicitly close all channels created with this function.
Closing the channel flushes the data and closes the underlying file
descriptor (unless it has already been closed, in which case the
buffered data is lost).*)
Closing the channel [oc] returned by [out_channel_of_descr fd]
using [close_out oc] also closes the underlying descriptor [fd].
Closing both the channel [oc] and the descriptor [fd] is incorrect
and will result in a {!Stdlib.Sys_error} or {!Unix.error}
exception.

See {!Unix.in_channel_of_descr} for a discussion of the closing
protocol when several channels are created on the same descriptor.
*)

val descr_of_in_channel : in_channel -> file_descr
(** Return the descriptor corresponding to an input channel. *)
Expand Down Expand Up @@ -1587,14 +1606,23 @@ val open_connection : sockaddr -> in_channel * out_channel
(** Connect to a server at the given address.
Return a pair of buffered channels connected to the server.
Remember to call {!Stdlib.flush} on the output channel at the right
times to ensure correct synchronization. *)
times to ensure correct synchronization.

The two channels returned by [open_connection] share a descriptor
to a socket. Therefore, when the connection is over, you should
call {!Stdlib.close_out} on the output channel, which will also close
the underlying socket. Do not call {!Stdlib.close_in} on the input
channel; it will be collected by the GC eventually.
*)


val shutdown_connection : in_channel -> unit
(** ``Shut down'' a connection established with {!open_connection};
that is, transmit an end-of-file condition to the server reading
on the other side of the connection. This does not fully close the
file descriptor associated with the channel, which you must remember
to free via {!Stdlib.close_in}. *)
on the other side of the connection. This does not close the
socket and the channels used by the connection.
See {!Unix.open_connection} for how to close them once the
connection is over. *)

val establish_server :
(in_channel -> out_channel -> unit) -> sockaddr -> unit
Expand All @@ -1604,6 +1632,13 @@ val establish_server :
is created for each connection. The function {!establish_server}
never returns normally.

The two channels given to the function share a descriptor to a
socket. The function does not need to close the channels, since this
occurs automatically when the function returns. If the function
prefers explicit closing, it should close the output channel using
{!Stdlib.close_out} and leave the input channel unclosed,
for reasons explained in {!Unix.in_channel_of_descr}.

On Windows: not implemented (use threads). *)


Expand Down