
  [;1m-spec monitor(process, monitor_process_identifier()) -> MonitorRef[0m
  [;1m                 when MonitorRef :: reference();[0m
  [;1m             (port, monitor_port_identifier()) -> MonitorRef[0m
  [;1m                 when MonitorRef :: reference();[0m
  [;1m             (time_offset, clock_service) -> MonitorRef[0m
  [;1m                 when MonitorRef :: reference().[0m

[;;4mSince[0m:
  OTP 18.0,OTP 19.0

  Types:
    -type monitor_port_identifier() :: port() | registered_name().
    -type monitor_process_identifier() ::
          pid() | registered_process_identifier().
    -type registered_name() :: atom().
    -type registered_process_identifier() ::
          registered_name() | {registered_name(), node()}.

  Sends a monitor request of type [;;4mType[0m to the entity identified by [;;4m[0m
  [;;4mItem[0m. If the monitored entity does not exist or it changes
  monitored state, the caller of [;;4mmonitor/2[0m is notified by a
  message on the following format:

    {Tag, MonitorRef, Type, Object, Info}

  Note:
    The monitor request is an asynchronous signal. That is, it
    takes time before the signal reaches its destination.

  [;;4mType[0m can be one of the following atoms: [;;4mprocess[0m, [;;4mport[0m or [;;4m[0m
  [;;4mtime_offset[0m.

  A [;;4mprocess[0m or [;;4mport[0m monitor is triggered only once, after that
  it is removed from both monitoring process and the monitored
  entity. Monitors are fired when the monitored process or port
  terminates, does not exist at the moment of creation, or if the
  connection to it is lost. If the connection to it is lost, we do
  not know if it still exists. The monitoring is also turned off
  when demonitor/1 is called.

  A [;;4mprocess[0m or [;;4mport[0m monitor by name resolves the [;;4mRegisteredName[0m
  to [;;4mpid()[0m or [;;4mport()[0m only once at the moment of monitor
  instantiation, later changes to the name registration will not
  affect the existing monitor.

  When a [;;4mprocess[0m or [;;4mport[0m monitor is triggered, a [;;4m'DOWN'[0m
  message is sent that has the following pattern:

    {'DOWN', MonitorRef, Type, Object, Info}

  In the monitor message [;;4mMonitorRef[0m and [;;4mType[0m are the same as
  described earlier, and:

  [;;4m[;;4mObject[0m[0m:
    The monitored entity, which triggered the event. When
    monitoring a process or a local port, [;;4mObject[0m will be equal
    to the [;;4mpid()[0m or [;;4mport()[0m that was being monitored. When
    monitoring process or port by name, [;;4mObject[0m will have format [;;4m[0m
    [;;4m{RegisteredName, Node}[0m where [;;4mRegisteredName[0m is the name
    which has been used with [;;4mmonitor/2[0m call and [;;4mNode[0m is local
    or remote node name (for ports monitored by name, [;;4mNode[0m is
    always local node name).

  [;;4m[;;4mInfo[0m[0m:
    Either the exit reason of the process, [;;4mnoproc[0m (process or
    port did not exist at the time of monitor creation), or [;;4m[0m
    [;;4mnoconnection[0m (no connection to the node where the monitored
    process resides).

  [;;4mMonitoring a [;;4mprocess[0m[0m:
    Creates monitor between the current process and another
    process identified by [;;4mItem[0m, which can be a [;;4mpid()[0m (local or
    remote), an atom [;;4mRegisteredName[0m or a tuple [;;4m{RegisteredName,[0m
    [;;4mNode}[0m for a registered process, located elsewhere.

    Change:
      Before ERTS 10.0 (OTP 21.0), monitoring a process could
      fail with [;;4mbadarg[0m if the monitored process resided on a
      primitive node (such as erl_interface or jinterface),
      where remote process monitoring is not implemented.

      Now, such a call to [;;4mmonitor[0m will instead succeed and a
      monitor is created. But the monitor will only supervise
      the connection. That is, a [;;4m{'DOWN', _, process, _,[0m
      [;;4mnoconnection}[0m is the only message that may be received,
      as the primitive node have no way of reporting the status
      of the monitored process.

  [;;4mMonitoring a [;;4mport[0m[0m:
    Creates monitor between the current process and a port
    identified by [;;4mItem[0m, which can be a [;;4mport()[0m (only local), an
    atom [;;4mRegisteredName[0m or a tuple [;;4m{RegisteredName, Node}[0m for
    a registered port, located on this node. Note, that attempt to
    monitor a remote port will result in [;;4mbadarg[0m.

  [;;4mMonitoring a [;;4mtime_offset[0m[0m:
    Monitors changes in [;;4mtime offset[0m between Erlang monotonic
    time and Erlang system time. One valid [;;4mItem[0m exists in
    combination with the [;;4mtime_offset Type[0m, namely the atom [;;4m[0m
    [;;4mclock_service[0m. Notice that the atom [;;4mclock_service[0m is not
    the registered name of a process. In this case it serves as an
    identifier of the runtime system internal clock service at
    current runtime system instance.

    The monitor is triggered when the time offset is changed. This
    either if the time offset value is changed, or if the offset
    is changed from preliminary to final during finalization of
    the time offset when the single time warp mode is used.
    When a change from preliminary to final time offset is made,
    the monitor is triggered once regardless of whether the time
    offset value was changed or not.

    If the runtime system is in multi time warp mode, the time
    offset is changed when the runtime system detects that the OS
    system time has changed. The runtime system does, however,
    not detect this immediately when it occurs. A task checking
    the time offset is scheduled to execute at least once a
    minute, so under normal operation this is to be detected
    within a minute, but during heavy load it can take longer
    time.

    The monitor is not automatically removed after it has been
    triggered. That is, repeated changes of the time offset
    trigger the monitor repeatedly.

    When the monitor is triggered a [;;4m'CHANGE'[0m message is sent to
    the monitoring process. A [;;4m'CHANGE'[0m message has the following
    pattern:

      {'CHANGE', MonitorRef, Type, Item, NewTimeOffset}

    where [;;4mMonitorRef[0m, [;;4mType[0m, and [;;4mItem[0m are the same as
    described above, and [;;4mNewTimeOffset[0m is the new time offset.

    When the [;;4m'CHANGE'[0m message has been received you are
    guaranteed not to retrieve the old time offset when calling [;;4m[0m
    [;;4merlang:time_offset()[0m. Notice that you can observe the change
    of the time offset when calling [;;4merlang:time_offset()[0m before
    you get the [;;4m'CHANGE'[0m message.

  Making several calls to [;;4mmonitor/2[0m for the same [;;4mItem[0m and/or [;;4m[0m
  [;;4mType[0m is not an error; it results in as many independent
  monitoring instances.

  The monitor functionality is expected to be extended. That is,
  other [;;4mType[0ms and [;;4mItem[0ms are expected to be supported in a future
  release.

  Note:
    If or when [;;4mmonitor/2[0m is extended, other possible values for [;;4m[0m
    [;;4mTag[0m, [;;4mObject[0m, and [;;4mInfo[0m in the monitor message will be
    introduced.

  Note:
    For some important information about distributed signals, see
    the Blocking Signaling Over Distribution section in the 
    Processes chapter of the Erlang Reference Manual.

  [;1m-spec monitor(process, monitor_process_identifier(), [monitor_option()]) ->[0m
  [;1m                 MonitorRef[0m
  [;1m                 when MonitorRef :: reference();[0m
  [;1m             (port, monitor_port_identifier(), [monitor_option()]) ->[0m
  [;1m                 MonitorRef[0m
  [;1m                 when MonitorRef :: reference();[0m
  [;1m             (time_offset, clock_service, [monitor_option()]) ->[0m
  [;1m                 MonitorRef[0m
  [;1m                 when MonitorRef :: reference().[0m

[;;4mSince[0m:
  OTP 24.0

  Types:
    -type monitor_port_identifier() :: port() | registered_name().
    -type monitor_process_identifier() ::
          pid() | registered_process_identifier().
    -type registered_name() :: atom().
    -type registered_process_identifier() ::
          registered_name() | {registered_name(), node()}.

  Provides an option list for modification of monitoring
  functionality provided by [;;4mmonitor/2[0m. The [;;4mType[0m and [;;4mItem[0m
  arguments have the same meaning as when passed to [;;4mmonitor/2[0m.
  Currently available options:

  [;;4m[;;4m{alias, UnaliasOpt}[0m[0m:
    The returned monitor reference will also become an alias for
    the calling process. That is, the returned reference can be
    used for sending messages to the calling process. See also [;;4m[0m
    [;;4malias/0[0m. The [;;4mUnaliasOpt[0m determines how the alias should be
    deactivated.

    [;;4m[;;4mexplicit_unalias[0m[0m:
      Only an explicit call to [;;4munalias/1[0m will deactivate the
      alias.

    [;;4m[;;4mdemonitor[0m[0m:
      The alias will be automatically deactivated when the
      monitor is removed. This either via an explicit call to [;;4m[0m
      [;;4mdemonitor/1[0m or when it is automatically removed at the
      same time as a [;;4m'DOWN'[0m message is delivered due to the
      monitor. The alias can also still be deactivated via a
      call to [;;4munalias/1[0m.

    [;;4m[;;4mreply_demonitor[0m[0m:
      The alias will be automatically deactivated when the
      monitor is removed (see [;;4mdemonitor[0m option above) or a
      reply message sent via the alias is received. When a reply
      message is received via the alias the monitor will also be
      automatically removed. This is useful in client/server
      scenarios when a client monitors the server and will get
      the reply via the alias. Once the response is received
      both the alias and the monitor will be automatically
      removed regardless of whether the response is a reply or a [;;4m[0m
      [;;4m'DOWN'[0m message. The alias can also still be deactivated
      via a call to [;;4munalias/1[0m. Note that if the alias is
      removed using the [;;4munalias/1[0m BIF, the monitor will still
      be left active.

    Example:

      server() ->
          receive
              {request, AliasReqId, Request} ->
                  Result = perform_request(Request),
                  AliasReqId ! {reply, AliasReqId, Result}
          end,
          server().
      
      client(ServerPid, Request) ->
          AliasMonReqId = monitor(process, ServerPid, [{alias, reply_demonitor}]),
          ServerPid ! {request, AliasMonReqId, Request},
          %% Alias as well as monitor will be automatically deactivated if we
          %% receive a reply or a 'DOWN' message since we used 'reply_demonitor'
          %% as unalias option...
          receive
              {reply, AliasMonReqId, Result} ->
                  Result;
              {'DOWN', AliasMonReqId, process, ServerPid, ExitReason} ->
                  error(ExitReason)
          end.

    Note that both the server and the client in this example must
    be executing on at least OTP 24 systems in order for this to
    work.

    For more information on process aliases see the Process
    Aliases section of the Erlang Reference Manual.

  [;;4m[;;4m{tag, UserDefinedTag}[0m[0m:
    Replace the default [;;4mTag[0m with [;;4mUserDefinedTag[0m in the 
    monitor message delivered when the monitor is triggered. For
    example, when monitoring a process, the [;;4m'DOWN'[0m tag in the
    down message will be replaced by [;;4mUserDefinedTag[0m.

    An example of how the [;;4m{tag, UserDefinedTag}[0m option can be
    used in order to enable the new selective receive
    optimization, introduced in OTP 24, when making multiple
    requests to different servers:

      server() ->
          receive
              {request, From, ReqId, Request} ->
                  Result = perform_request(Request),
                  From ! {reply, self(), ReqId, Result}
          end,
          server().
      
      client(ServerPids, Request) when is_list(ServerPids) ->
          ReqId = make_ref(),
          lists:foreach(fun (ServerPid) ->
                                _ = monitor(process, ServerPid,
                                            [{tag, {'DOWN', ReqId}}]),
                                ServerPid ! {request, self(), ReqId, Request}
                        end,
                        ServerPids),
          receive_replies(ReqId, length(ServerPids), []).
      
      receive_replies(_ReqId, 0, Acc) ->
          Acc;
      receive_replies(ReqId, N, Acc) ->
          %% The compiler will detect that we match on the 'ReqId'
          %% reference in all clauses, and will enable the selective
          %% receive optimization which makes the receive able to
          %% skip past all messages present in the message queue at
          %% the time when the 'ReqId' reference was created...
          Res = receive
                    {reply, ServerPid, ReqId, Result} ->
                        %% Here we typically would have deactivated the
                        %% monitor by a call to demonitor(Mon, [flush]) but
                        %% we ignore this in this example for simplicity...
                        {ok, ServerPid, Result};
                    {{'DOWN', ReqId}, _Mon, process, ServerPid, ExitReason} ->
                        {error, ServerPid, ExitReason}
                end,
          receive_replies(ReqId, N-1, [Res | Acc]).

    In order for this example to work as intended, the client must
    be executing on at least an OTP 24 system, but the servers may
    execute on older systems.
