erlang:port_command函数

阅读更多
今天读到 褚霸博客里的 gen_tcp:send的深度解刨和使用指南(初稿)时,顺着霸爷的思路,跟着
lib/kernel/src/gen_tcp.erl
send(S, Packet) when is_port(S) ->
    case inet_db:lookup_socket(S) of
	{ok, Mod} ->
	    Mod:send(S, Packet);
	Error ->
	    Error
    end.


lib/kernel/src/inet_tcp.erl
%%
%% Send data on a socket
%%
send(Socket, Packet, Opts) -> prim_inet:send(Socket, Packet, Opts).
send(Socket, Packet) -> prim_inet:send(Socket, Packet, []).

erts/preloaded/src/prim_inet.erl
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% SEND(insock(), Data) -> ok | {error, Reason}
%%
%% send Data on the socket (io-list)
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This is a generic "port_command" interface used by TCP, UDP, SCTP, depending
%% on the driver it is mapped to, and the "Data". It actually sends out data,--
%% NOT delegating this task to any back-end.  For SCTP, this function MUST NOT
%% be called directly -- use "sendmsg" instead:
%%
send(S, Data, OptList) when is_port(S), is_list(OptList) ->
    ?DBG_FORMAT("prim_inet:send(~p, ~p)~n", [S,Data]),
    try erlang:port_command(S, Data, OptList) of
	false -> % Port busy and nosuspend option passed
	    ?DBG_FORMAT("prim_inet:send() -> {error,busy}~n", []),
	    {error,busy};
	true ->
	    receive
		{inet_reply,S,Status} ->
		    ?DBG_FORMAT("prim_inet:send() -> ~p~n", [Status]),
		    Status
	    end
    catch
	error:_Error ->
	    ?DBG_FORMAT("prim_inet:send() -> {error,einval}~n", []),
	     {error,einval}
    end.

看到了使用erlang:port_command/3来向ERTS发送数据,根据erlang:port_command的文档的说明,
引用

      port_command(Port, Data, OptionList) -> boolean()

              Types:

                 Port = port() | atom()
                 Data = iodata()
                 Option = force | nosuspend
                 OptionList = [Option]

              Sends  data  to  a  port.  port_command(Port, Data, [])
              equals port_command(Port, Data).

              If the port command is aborted false is returned;  oth-
              erwise, true is returned.

              If  the  port is busy, the calling process will be sus-
              pended until the port is not busy anymore.

              Currently the following Options are valid:

                force:
                  The calling process will not be  suspended  if  the
                  port  is  busy; instead, the port command is forced
                  through. The call will fail with a notsup exception
                  if  the  driver  of the port does not support this.
                  For more information see the ERL_DRV_FLAG_SOFT_BUSY
                  driver flag.

                nosuspend:
                  The  calling  process  will not be suspended if the
                  port is busy; instead, the port command is  aborted
                  and false is returned.

我们知道OptionList可以是force和nosuspend,当设置该选项时,如果port处于busy状态,该调用进程不会被挂起,而是会强制执行,如果这个端口的驱动不支持该行为的话,调用程序将收到一个notsup的异常;当nosuspend选项被设置时,如果port处于busy状态,调用进程不会被挂起,而是收到false的返回。

而在erlang:system_monitor/2中,
引用

       erlang:system_monitor(MonitorPid, Options) -> MonSettings

              Types:

                 MonitorPid = pid()
                 Options = [system_monitor_option()]
                 MonSettings =  undefined  |  {OldMonitorPid,  OldOp-
                 tions}
                 OldMonitorPid = pid()
                 OldOptions = [system_monitor_option()]
                 system_monitor_option() = busy_port
                                         | busy_dist_port
                                         | {long_gc, integer() >= 0}
                                         | {long_schedule, integer() >= 0}
                                         | {large_heap, integer() >= 0}
.....
                busy_port:
                  If  a  process in the system gets suspended because
                  it sends to a busy port, a message  {monitor,  Sus-
                  Pid, busy_port, Port} is sent to MonitorPid. SusPid
                  is the pid that got suspended when sending to Port.

如果设置了busy_port选项时,当被monitor的进程因为调用的port处于busy状态而被挂起时,monitor进程会收到{monitor,  SusPid, busy_port, Port}消息,SusPid是被监控的进程ID

你可能感兴趣的:(erlang,gen_tcp,port)