mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-17 02:13:54 +00:00
A call to channel.untake will deadlock if a call to channel.take is blocked on the same channel. unGetChan was removed from GHC for the same reason: https://gitlab.haskell.org/ghc/ghc/issues/4154 library/thread.channel.m: Deprecate channel.untake/4. NEWS: Announce the change.
133 lines
4.2 KiB
Mathematica
133 lines
4.2 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 The Mercury team.
|
|
% This file is distributed under the terms specified in COPYING.LIB.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: thread.channel.m.
|
|
% Main author: petdr.
|
|
% Stability: low.
|
|
%
|
|
% A mvar can only contain a single value, a channel on the other hand provides
|
|
% unbounded buffering.
|
|
%
|
|
% For example a program could consist of 2 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, block if there is
|
|
% nothing in the channel.
|
|
%
|
|
:- pred take(channel(T)::in, T::out, io::di, io::uo) is det.
|
|
|
|
% Take an item from the start of the channel.
|
|
% Returns immediately with no if the channel was empty.
|
|
%
|
|
:- 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.
|
|
%
|
|
:- pragma obsolete(untake/4).
|
|
:- pred untake(channel(T)::in, T::in, io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- 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.
|
|
).
|
|
|
|
channel.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).
|
|
|
|
channel.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).
|
|
|
|
channel.take(channel(Read, _Write), Val, !IO) :-
|
|
mvar.take(Read, Head, !IO),
|
|
mvar.take(Head, item(Val, NewHead), !IO),
|
|
mvar.put(Read, NewHead, !IO).
|
|
|
|
channel.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).
|
|
|
|
channel.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).
|
|
|
|
channel.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).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|