设为首页 收藏本站
查看: 982|回复: 0

[经验分享] 探密perl-解析perl源码(2)

[复制链接]

尚未签到

发表于 2017-5-17 06:03:29 | 显示全部楼层 |阅读模式
  本系列为刘兴(http://deepfuture.iteye.com/)原创,未经笔者授权,任何人和机构不能转载 
1、
1)Perl本身有三种主要的数据类型:
标量(scalar)
数组(array)
散列(hash)
这三种类型在perlapi中对应有三种:
SV(Scalar Variables)
AV(Array Variables)
HV(Hash Variables)
2)指令标志
IA64处理器I-tanium(安腾)
X64 64位的处理器.
X32 32位的处理器.
i32 32位的操作系统

3)perlapi.h
  #undef  PL_OpPtr
#define PL_OpPtr  (*Perl_IOpPtr_ptr(aTHX))
#undef  PL_OpSlab
#define PL_OpSlab  (*Perl_IOpSlab_ptr(aTHX))
  2、分配perl片区内存
  片区大小PERL_SLAB_SIZE*sizeof(I32*),PERL_SLAB_SIZE在READONLY调试模式,默认为4096,否则为2048
  

  #ifdef PERL_DEBUG_READONLY_OPS
  #  define PERL_SLAB_SIZE 4096
  #  include <sys/mman.h>
  #endif
  

  #ifndef PERL_SLAB_SIZE
  #define PERL_SLAB_SIZE 2048
  #endif
  void *
  Perl_Slab_Alloc(pTHX_ size_t sz)
  {
  //传入的sz参数是指分配的片区大小(字节为单位)
      dVAR;//ifdef PERL_GLOBAL_STRUCT,则完成 my_vars赋值
  //my_vars赋值:struct perl_vars*my_vars= (struct perl_vars*)PERL_GET_VARS()
      /*
  PL_OpPtr指向指令集合池中的某条I32指令的地址PL_OpSlab
  PL_OpSlab保存了具体该条I32指令地址
  PL_OpPtr和PL_OpSlab都是指针,PL_OpSlab指向某条最终指令的地址
  I32指令是一个结构变量,含有该指令的信息
  当增加某条指令时,从指令集合池中分配一个指针大小的空间存放该条指令的指针PL_OpSlab
       * To make incrementing use count easy PL_OpSlab is an I32 *
       * To make inserting the link to slab PL_OpPtr is I32 **
       * So compute size in units of sizeof(I32 *) as that is how Pl_OpPtr increments
       * Add an overhead for pointer to slab and round up as a number of pointers
       */
      //将函数参数sz改为I32指令数量,在函数参数基础上加了2条指令
      sz = (sz + 2*sizeof(I32 *) -1)/sizeof(I32 *);
  

  if ((PL_OpSpace -= sz) < 0) {//PL_OpSpace空间太小,分配新片区(即指令指针池),片区内仅存放指令指针
        //如果PL_OpSpace空间不能容纳本次分配的片区,则分配新的片区
       //PERL_SLAB_SIZE为新片区指令总数量  
  #ifdef PERL_DEBUG_READONLY_OPS//如果是调试模式
  /* We need to allocate chunk by chunk so that we can control the VM
    mapping */
       //定义了只读调试,则将PERL_SLAB_SIZE*sizeof(I32*)的大小的片区映射到内存,地址返回给PL_OpPtr(I32 **类型)
  

  

  

  PL_OpPtr = (I32**) mmap(0, PERL_SLAB_SIZE*sizeof(I32*), PROT_READ|PROT_WRITE,
  MAP_ANON|MAP_PRIVATE, -1, 0);
         //打印OP调试信息,其中包括片区大小和片区起始地址
  DEBUG_m(PerlIO_printf(Perl_debug_log, "mapped %lu at %p\n",
       (unsigned long) PERL_SLAB_SIZE*sizeof(I32*),
       PL_OpPtr));
  if(PL_OpPtr == MAP_FAILED) {
     perror("mmap failed");
     abort();
  }
  #else
  如果不是调试模式,直接分配PERL_SLAB_SIZE*sizeof(I32*)大小空间
  该空间容纳PERL_SLAB_SIZE 条指令(不是指令结构变量本身,而是指令结构变量的指针)
          PL_OpPtr = (I32 **) PerlMemShared_calloc(PERL_SLAB_SIZE,sizeof(I32*));
  //iperlsys.h找到PerlMemShared_calloc相关定义
  #define PerlMemShared_calloc(num, size)    \
  (*PL_MemShared->pCalloc)(PL_MemShared, (num), (size))
  #endif
       if (!PL_OpPtr) {//PL_OpPtr分配错误,返回NULL
     return NULL;
  }
  //接着处理分配的PERL_SLAB_SIZE*sizeof(I32*)大小空间
  /* We reserve the 0'th I32 sized chunk as a use count */
          //PL_OpSlab从PL_OpPtr获得指令地址
          PL_OpSlab = (I32 *) PL_OpPtr;
  /* Reduce size by the use count word, and by the size we need.
  * Latter is to mimic the '-=' in the if() above
  */
          //PL_OpSpace 为余下的空间,重新计算
  PL_OpSpace = PERL_SLAB_SIZE - (sizeof(I32)+sizeof(I32 **)-1)/sizeof(I32 **) - sz;
  /* Allocation pointer starts at the top.
    Theory: because we build leaves before trunk allocating at end
    means that at run time access is cache friendly upward
  */
          //PL_OpPtr指向片区空间(即指令指针池)的未尾,因为空间容纳了PERL_SLAB_SIZE个I32指令结构地址(I32*)
  PL_OpPtr += PERL_SLAB_SIZE;
  //处理在只读调试的情况下,新增片区,需要放置相关片区地址在PL_slabs数组中(仅用于调试),该数组存放了所有曾经分配过的OP片区,注意不是PL_OpSlab
  #ifdef PERL_DEBUG_READONLY_OPS
  /* We remember this slab.  */
  /* This implementation isn't efficient, but it is simple. */
  PL_slabs = (I32**) realloc(PL_slabs, sizeof(I32**) * (PL_slab_count + 1));
  PL_slabs[PL_slab_count++] = PL_OpSlab;
  DEBUG_m(PerlIO_printf(Perl_debug_log, "Allocate %p\n", PL_OpSlab));
  #endif
  }
      assert( PL_OpSpace >= 0 );//确保PL_OpSpace还有空间容纳I32指令
     //新分配空间或原有空间已经足够容纳,处理返回值(void *)(PL_OpPtr + 1)
      /* Move the allocation pointer down */
      PL_OpPtr   -= sz;//分配片区空间的使用是从未尾开始向前推进,即从后向前使用空间,PL_OpPtr指向本次从片区空间中分配的指令集合所使用的空间的起始地址
      assert( PL_OpPtr > (I32 **) PL_OpSlab );//确保本次分配的指令集合空间够用,
  //没有超过片区的起始地址(I32 **) PL_OpSlab
     //本次分配的空间起始地址放置片区空间首指令( I32*)PL_OpSlab
      *PL_OpPtr   = PL_OpSlab; /* Note which slab it belongs to */
  //PL_OpSlab是(I32*)
     (*PL_OpSlab)++; /* Increment use count of slab */
      assert( PL_OpPtr+sz <= ((I32 **) PL_OpSlab + PERL_SLAB_SIZE) );
      assert( *PL_OpSlab > 0 );
      return (void *)(PL_OpPtr + 1);//因为*PL_OpPtr处放置了片区空间首指令PL_OpSlab,必须以下一个指令指针位置,返回给函数调用者
  }
  
DSC0000.png

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-378216-1-1.html 上篇帖子: Perl Language(I)Beginning of Perl 下篇帖子: 初识Perl/Catalyst
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表