function poolStartupErr = initThreadWorker(hostname, parentStreamIdxVector, workerUuids, isBackgroundWorker)
% Worker-side function to initialize all internal worker-side constant state for a
% thread-based parallel pool.
%
% This includes:
%  1. Default RNG
%  2. Default GPU device selection
%  3. PoolStartup.

%   Copyright 2020-2021 The MathWorks, Inc.

% Default RNG
parallel.internal.pool.initWorkerRandStream(parentStreamIdxVector, workerUuids, isBackgroundWorker);

% Default GPU device selection
iInitGpuMediator(hostname, workerUuids);

% Finally, poolStartup
if ~isBackgroundWorker
    poolStartupErr = iRunCustomPoolStartup();
else
    poolStartupErr = [];
end

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function iInitGpuMediator(hostname, workerUuids)
% Initialize default GPU device selection
[~, labIdx] = ismember(parallel.internal.pool.workerUuid(), workerUuids);
numLabs = numel(workerUuids);
mediator = parallel.internal.pool.GPUClusterMediator.getInstance();
mediator.HostName = hostname;
mediator.MachineToWorkerMapping = [repmat({hostname}, 1, numLabs); num2cell(1:numLabs)];
mediator.StoredLabIndex = labIdx;
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function err = iRunCustomPoolStartup()
% Run the poolStartup script if present
if ~exist("poolStartup.m", "file")
    return;
end

try
    poolStartup
    err = MException.empty;
catch err
    stackToIgnore = "parallel.internal.pool.initThreadWorker";
    err = ParallelException.hBuildFromRemoteException(err, stackToIgnore);
    poolStartupMsg = message("parallel:job:PoolStartupUserError", which("poolStartup.m"));
    err = addCause(MException(poolStartupMsg), err);
end

end