Files
mercury/library/thread.channel.m
Julien Fischer 77c95ee27a Avoid unnecessary module qualification.
library/thread.channel.m:
    As above.
2026-04-10 22:59:03 +10:00

136 lines
4.3 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%---------------------------------------------------------------------------%
% Copyright (C) 2000-2001, 2006-2007 The University of Melbourne.
% Copyright (C) 2014-2015, 2018, 2020-2022, 2025-2026 The Mercury team.
% This file is distributed under the terms specified in COPYING.LIB.
%---------------------------------------------------------------------------%
%
% File: thread.channel.m.
% Main author: petdr.
% Stability: medium.
%
% An mvar can contain only a single value. On the other hand,
% a channel provides unbounded buffering.
%
% For example, a program could consist of two worker threads and one logging
% thread. The worker threads can place messages into the channel, and they
% will be buffered for processing by the logging thread.
%
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- module thread.channel.
:- interface.
:- import_module io.
:- import_module maybe.
%---------------------------------------------------------------------------%
:- type channel(T).
% Initialise a channel.
%
:- pred init(channel(T)::out, io::di, io::uo) is det.
% Put an item at the end of the channel.
%
:- pred put(channel(T)::in, T::in, io::di, io::uo) is det.
% Take an item from the start of the channel.
% If there is nothing in the channel, block.
%
:- pred take(channel(T)::in, T::out, io::di, io::uo) is det.
% Take an item from the start of the channel.
% If there is nothing in the channel, return "no" immediately.
%
:- pred try_take(channel(T)::in, maybe(T)::out, io::di, io::uo) is det.
% Duplicate a channel. The new channel sees all (and only) the
% data written to the channel after the `duplicate'/4 call.
%
:- pred duplicate(channel(T)::in, channel(T)::out, io::di, io::uo)
is det.
% Place an item back at the start of the channel.
%
% WARNING: a call to channel.untake will deadlock if a call to
% channel.take is blocked on the same channel.
%
:- pred untake(channel(T)::in, T::in, io::di, io::uo) is det.
:- pragma obsolete(pred(untake/4)).
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
:- import_module thread.mvar.
%---------------------------------------------------------------------------%
:- type channel(T)
---> channel(
mvar(stream(T)), % Read end.
mvar(stream(T)) % Write end.
).
:- type stream(T) == mvar(item(T)).
:- type item(T)
---> item(
T, % The current item.
stream(T) % The rest of the stream.
).
%---------------------------------------------------------------------------%
init(channel(Read, Write), !IO) :-
mvar.init(Read, !IO),
mvar.init(Write, !IO),
mvar.init(Hole, !IO),
mvar.put(Read, Hole, !IO),
mvar.put(Write, Hole, !IO).
put(channel(_Read, Write), Val, !IO) :-
mvar.init(NewHole, !IO),
mvar.take(Write, OldHole, !IO),
mvar.put(Write, NewHole, !IO),
mvar.put(OldHole, item(Val, NewHole), !IO).
take(channel(Read, _Write), Val, !IO) :-
mvar.take(Read, Head, !IO),
mvar.take(Head, item(Val, NewHead), !IO),
mvar.put(Read, NewHead, !IO).
try_take(channel(Read, _Write), MaybeVal, !IO) :-
mvar.take(Read, Head, !IO),
mvar.try_take(Head, MaybeItem, !IO),
(
MaybeItem = yes(item(Val, NewHead)),
MaybeVal = yes(Val)
;
MaybeItem = no,
MaybeVal = no,
NewHead = Head
),
mvar.put(Read, NewHead, !IO).
duplicate(channel(_Read, Write), channel(NewRead, Write), !IO) :-
mvar.init(NewRead, !IO),
mvar.take(Write, Hole, !IO),
mvar.put(Write, Hole, !IO),
mvar.put(NewRead, Hole, !IO).
untake(channel(Read, _Write), Val, !IO) :-
mvar.init(NewHead, !IO),
mvar.take(Read, Head, !IO),
mvar.put(NewHead, item(Val, Head), !IO),
mvar.put(Read, NewHead, !IO).
%---------------------------------------------------------------------------%
:- end_module thread.channel.
%---------------------------------------------------------------------------%