function c = mutex(name, varargin)
%MUTEX Create a mutex to control access to global, shared data. 
%
%   M = mps.sync.mutex(NAME, 'Connection', CONNECTION) creates a named
%   mutex in the persistence service identified by CONNECTION. Multiple
%   MATLAB Production Server workers may cooperatively coordinate access 
%   to one or more shared cache variables with a mutex. 
%
%   Workers cooperate by attempting to acquire a lock on the mutex. Only
%   one worker may own the mutex lock. The other workers must wait and try
%   again. The lock-owning worker may modify the protected data safely. 
%
%   Since a MATLAB Production Server instance is a distributed system, and
%   a worker crash or hang is possible, all locks eventually expire to
%   prevent deadlock. The default lock expiration time is 10 seconds.
%
%   M = mps.sync.mutex(..., 'Expiration', SECONDS) creates a mutex with an
%   expiration time of SECONDS seconds. Once locked, the mutex will only
%   remain locked for the expiration time interval, after which point it
%   may be locked again.
%
%   Example:
%
%   Create and attempt to lock a mutex named 'RadarLock' in the 
%   persistence service identified by connection 'AerospaceStorage':
%
%       m = mps.sync.mutex('RadarLock','Connection','AerospaceStorage');
%       tf = acquire(m);
%
%   If tf is true, the caller owns the lock, until it expires.
%
%   Note: a mutex provides a mechanism for MPS workers to cooperatively
%   manage shared data. The mutex does not "lock" the persistence server or
%   prevent any kind of access to cached data. Workers that do not use the
%   mutex or use it incorrectly may corrupt shared data.
%   
%   See Also ServiceMutex, mps.cache.connect

% Copyright 2018 The MathWorks, Inc.

    import mps.cache.internal.InputValidator;
    
    p = inputParser;
    p.KeepUnmatched = true;
    
    % Cache name is required.
    addRequired(p,'name',InputValidator.ValidVariableName);
             
    % addParameter requires a default value. 
    defaultConnection = ' ';
    addParameter(p,'Connection',defaultConnection, ...
        InputValidator.NonEmptyString);
    
    defaultExpiration = 10;
    addParameter(p,'Expiration',defaultExpiration, ...
        InputValidator.ScalarInteger);
    
    % Validate Connection and Cache.
    parse(p,name,varargin{:});

    % Connection may only be omitted if there is only one known Connection in
    % the list of connections stored by the mps.cache.Connection class.
    if ismember('Connection',p.UsingDefaults)
        ci = mps.cache.Connection.getInstance();
    else
        ci = mps.cache.Connection.getInstance(p.Results.Connection);
    end
    
    % Use the information in the connection to create a Mutex subclass
    % appropriate for the connection's provider.
    r = mps.cache.ProviderRegistry.getInstance();
    provider = get(r,ci.ProviderName);
    if isfield(provider,'TimedMutex')
        c = feval(provider.TimedMutex, name, ci, p.Results);
    else
        error(message('MPS:MATLAB:Sync:NoProviderSupport', ci.ProviderName));
    end
end
