ReacOS源代码阅读之驱动--atexit实现原理和机制

    之前的<<main函数执行前后--全局构造和atexit>>文章里说到atexit函数注册的函数是在main函数之后执行的,同时类似于栈,后注册的函数先执行。

    今天通过分析ReactOS的源代码,来验证这个结论吧。

    atexit函数注册的参数是通过C语言的函数指针,注册的函数是不带参数的。首先看看atexit注册机制的实现吧。

     注册的实现在 E:\Open_Source_Code\ReactOS\sdk\lib\crt\stdlib\atexit.c 源文件中。

     

/*********************************************************************
 *		_onexit (MSVCRT.@)
 */
_onexit_t CDECL _onexit(_onexit_t func)
{
  TRACE("(%p)\n",func);

  if (!func)
    return NULL;

  LOCK_EXIT;
  if (atexit_registered > atexit_table_size - 1)
  {
    _onexit_t *newtable;
    TRACE("expanding table\n");
    newtable = calloc(atexit_table_size + 32, sizeof(void *));
    if (!newtable)
    {
      TRACE("failed!\n");
      UNLOCK_EXIT;
      return NULL;
    }
    memcpy (newtable, atexit_table, atexit_table_size);
    atexit_table_size += 32;
    free (atexit_table);
    atexit_table = newtable;
  }
  atexit_table[atexit_registered] = func;
  atexit_registered++;
  UNLOCK_EXIT;
  return func;
}

/*********************************************************************
 *		atexit (MSVCRT.@)
 */
int CDECL atexit(void (*func)(void))
{
  TRACE("(%p)\n", func);
  return _onexit((_onexit_t)func) == (_onexit_t)func ? 0 : -1;
}
      如上代码,atexit函数的实现其实很简单,就是输入一个函数指针,内部实现调用 _onexit 函数,该函数首先判断已经分配的函数指针数组是否已经满了,如果是,那么多分配32个函数指针的空间。如下2句,就是把函数指针放入到指针数组的最后面,同时注册的函数指针数量+1。

        atexit_table[atexit_registered] = func;
        atexit_registered++; 

      接下来就是调用的问题了。在 E:\Open_Source_Code\ReactOS\sdk\lib\crt\startup\crtexe.c 文件中,定义了函数 __tmainCRTStartup,该函数是c运行时库的函数,在启动一个进程的时候由系统调用,这个函数会调用我们定义的main函数。同时也会调用我们通过atexit函数注册过的全部函数。

       

    __main ();
#ifdef WPRFLAG
    __winitenv = envp;
    /* C++ initialization.
       gcc inserts this call automatically for a function called main, but not for wmain.  */
    mainret = wmain (argc, argv, envp);
#else
    __initenv = envp;
    mainret = main (argc, argv, envp);
#endif
    if (!managedapp)
      exit (mainret);

    if (has_cctor == 0)
      _cexit ();

       如上代码片段,__tmainCRTStartup 函数先调用了了main函数,等main函数执行完成,退出后。又调用了 _cexit 函数,这个函数就会去调用我们通过atexit注册的函数。

      

void _cexit( void )
{
  LOCK_EXIT;
  __call_atexit();
  UNLOCK_EXIT;
}
   
_onexit_t *atexit_table = NULL;
int atexit_table_size = 0;
int atexit_registered = 0; /* Points to free slot */

/* INTERNAL: call atexit functions */
void __call_atexit(void)
{
  /* Note: should only be called with the exit lock held */
  TRACE("%d atext functions to call\n", atexit_registered);
  /* Last registered gets executed first */
  while (atexit_registered > 0)
  {
    atexit_registered--;
    TRACE("next is %p\n",atexit_table[atexit_registered]);
    if (atexit_table[atexit_registered])
      (*atexit_table[atexit_registered])();
    TRACE("returned\n");
  }
}

      上面的 __call_atexit 应该是不需要多余的解释了。通过这句  (*atexit_table[atexit_registered])(); 很明显说明了,后面注册的函数会先被调用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值