`
coderplay
  • 浏览: 571851 次
  • 性别: Icon_minigender_1
  • 来自: 广州杭州
社区版块
存档分类
最新评论

emulator调试日志: port篇

阅读更多
------------------ port 篇 -------------
open_port/2这个是由bif实现, 源文件在erl_bif_port.c中, 函数是BIF_RETTYPE open_port_2(BIF_ALIST_2)
其中:
#define BIF_RETTYPE Eterm
#define BIF_ALIST_2 Process* A__p, Eterm A_1, Eterm A_2

此函数调用了同文件中的
static int
open_port(Process* p, Eterm name, Eterm settings, int *err_nump)
函数.
name 对应 open_port/2的第一个参数PortName
setting 对应 open_port/2的第二个参数PortSettings
其中:
PortSettings = [Opt]
 Opt = {packet, N} | stream | {line, L} | {cd, Dir} | {env, Env} | exit_status | use_stdio | nouse_stdio | stderr_to_stdout | in | out | binary | eof
  N = 1 | 2 | 4
  L = int()
  Dir = string()
  Env = [{Name, Val}]
   Name = string()
   Val = string() | false
这些port的设置都由open_port函数Parse the settings注释后面的代码解析. erl_bif_port.c: 475行

第一个参数name的解析由open_port函数Parse the first argument and start the appropriate driver注释后面的代码解析. erl_bif_port.c: 590行
此处解析第一个参数name,并开启正确的driver
PortName = {spawn, Command} | {fd, In, Out}
分两种情况: spawn出来的进程, 使用文件描述符

spawn_driver_entry外部定义, spawn_driver_entry是名为spawn的driver的入口结构体. 它在linux平台上的定义在emulator/sys/unix/sys.c下
struct erl_drv_entry spawn_driver_entry = {
    spawn_init,
    spawn_start,
    stop,
    output,
    ready_input,
    ready_output,
    "spawn",
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    ERL_DRV_EXTENDED_MARKER,
    ERL_DRV_EXTENDED_MAJOR_VERSION,
    ERL_DRV_EXTENDED_MINOR_VERSION,
    ERL_DRV_FLAG_USE_PORT_LOCKING
};
erl_drv_entry这个结构体的定义的emulator/beam/erl_driver.h. 结构体的成员包括port初始化, 开始,停止, 取/出数据的各种函数指针(因为运行的平台不同,所以用指针来指定策略).
  
真正干活的是io.c下面的
/*
   Opens a driver.
   Returns the non-negative port number, if successful.
   If there is an error, -1 or -2 or -3 is returned. -2 means that
   there is valid error information in 'errno'.
   Returning -3 means that an error in the given options was detected.
   The driver start function must obey the same conventions.
*/
int
erts_open_driver(ErlDrvEntry* driver,    /* Pointer to driver entry. */
         Eterm pid,        /* Current process. */
         char* name,        /* Driver name. */
         SysDriverOpts* opts,    /* Options. */
         int *error_number_ptr)    /* errno in case -2 is returned */
函数. io.c: 505行
步骤:
    1. 获取一个free的port,取得一个port_num. 通过 static int get_free_port(void)函数来检查, 如果port的status属性为ERTS_PORT_S_FREE则这个port是free的
    2. 检查同名的driver是否已经存在.如果存在,则用已有的driver,如果不存在则用默认的spawn/fd driver
    3. drv_data = (*driver->start)((ErlDrvPort)port_num, name, opts); 初始化一些东西而已,比如driver名称,driver的io队列等
    4. 用已有的名为spawn的driver启动driver, drv_data = (*driver->start)((ErlDrvPort)port_num, name, opts); (unix/sys.c)
    5. clean up the port.
    6. 返回port_num.

附:名为efile的driver,它的struct erl_drv_entry结构体定义在emulator/drivers/comm/efile_drv.c中, 如下:
struct erl_drv_entry efile_driver_entry = {
    file_init,
    file_start,
    file_stop,
    file_output,
    NULL,
    NULL,
    "efile",
    NULL,
    NULL,
    file_control,
    file_timeout,
    file_outputv,
    file_async_ready,
    file_flush,
    NULL,
    NULL,
    ERL_DRV_EXTENDED_MARKER,
    ERL_DRV_EXTENDED_MAJOR_VERSION,
    ERL_DRV_EXTENDED_MINOR_VERSION,
    ERL_DRV_FLAG_USE_PORT_LOCKING,
    NULL
};
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics