:- pred master_loop_abort(
    par_bits(MasterCustomMsg, FeederCustomMsg, WorkerCustomMsg)::in,

    % Predicate which finishes the received result messages
    master_finish(MasterCustomMsg, FeederCustomMsg, WorkerCustomMsg, MasterData, Result)
    ::in(master_finish),

    % Number of running worker threads
    int::in, int::out,

    % If the feeder has exited
    bool::in, bool::out,

    % Custom data that's being maintained inside the master loop.
    MasterData::in, MasterData::out,

    % The exception which is being treated.
    Exc::in,

    io::di, io::uo
) is erroneous.

master_loop_abort(
    ParBits, Finish,
    !NumWorkers, !FeederExited, !MasterData,
    Exc,
    !IO
) :-
    log_format_mfwpar("master_loop_abort: !.NumWorkers = %i, !.FeederExited = %s",
        [i(!.NumWorkers), s(string(!.FeederExited))], !IO),

    (
        if
            !.NumWorkers = 0,
            !.FeederExited = yes
        then
            % No more workers or feeder. Call Finish to do cleanup and throw the exception out of
            % the master loop and out of "mfwpar".
            ignore_exceptions(
                (pred(!.IO1::di, !:IO1::uo) is cc_multi :-
                    Finish(ParBits, 'new abort'(Exc), !.MasterData, _, !IO1)),
                !IO
            ),
            throw(Exc)

        else
            % "worker_terminated" or "feeder_terminated" messages are awaited. Therefore we can wait
            % blockingly.
            priority_channel.take(ParBits ^ master_channel, Msg, !IO),
            (
                % A worker has terminated (or is terminating). Record that.
                Msg = worker_terminated,
                !:NumWorkers = !.NumWorkers - 1
            ;
                % The feeder has terminated (or is terminating). Record that.
                Msg = feeder_terminated,
                !:FeederExited = yes
            ;
                % Already aborting, ignore.
                Msg = abort(_)
            ;
                % Custom message is to be ignored.
                Msg = custom(_)
            ),

            master_loop_abort(
                ParBits, Finish,
                !NumWorkers, !FeederExited, !MasterData,
                Exc, !IO
            )
    ).
