Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15361065
  • 博文数量: 2005
  • 博客积分: 11986
  • 博客等级: 上将
  • 技术积分: 22535
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-17 13:56
文章分类

全部博文(2005)

文章存档

2014年(2)

2013年(2)

2012年(16)

2011年(66)

2010年(368)

2009年(743)

2008年(491)

2007年(317)

分类: LINUX

2009-05-18 21:31:44

浅析dbus-1.2.14数据8字节下对齐后数据搬移

不知道为什么这样一个经过如此长时间严克测试的dbus,开始还以为存在bug,
其实是自己对memmove()函数不熟悉,通过malloc或者calloc申请的内存首地址存可能为0x800002,
0x800002不在8字节边界上,所以dbus对该0x800002地址进行调整,调整有2种方式,将0x800002进行8字节上对齐,
即: (0x800002) & ~0x07 = 0x800000; // 8字节内存地址上对齐
另外一种就是8字节下对齐,
即: (0x800002 + 7) & ~0x07 = 0x800008; // 8字节内存地址下对齐
很明显malloc到的首地址为0x800002我们只能进行8字节内存地址下对齐调整,这也是dbus使用的,这没有什么问题,
以为bug发生在出现内存未8字节对齐之后进行内存数据搬移函数memmove的执行上[其实没有问题].
比如
old_str = 0x800002
new_str = 0x800008
len = 原有数据长度
看看dbus是怎么将old_str中的数据搬移到new_str的,
memmove (0x800002, 0x800008, len);原以为这样不就发生数据覆盖了吗,
其实memmove()函数已经解决了覆盖问题,当发现src小于dst时,memmove()就
从&src[len]和&dst[len]结尾开始倒着拷贝[luther.gliethttp].

void *memmove(void *dst, const void *src, size_t n)
{
  const char *p = src;
  char *q = dst;
  if (__builtin_expect(q < p, 1)) { // src 大于 dst,说明没有发生覆盖,直接从头部开始顺序拷贝即可.[luther.gliethttp]
    return memcpy(dst, src, n);
  } else {
      // src 小于 dst,如果顺序从头开始拷贝会发生数据覆盖,所以从尾部开始倒着拷贝.
#define PRELOAD_DISTANCE 64
      /* a semi-optimized memmove(). we're preloading the src and dst buffers
       * as we go */
    size_t c0, c1, i;
    p += n;
    q += n;
    /* note: we preload the destination as well, because the 1-byte at a time
     * copy below doesn't take advantage of the write-buffer, we need
     * to use the cache instead as a poor man's write-combiner */
    __builtin_prefetch(p-1);
    __builtin_prefetch(q-1);
    if (PRELOAD_DISTANCE > 32) {
        __builtin_prefetch(p-(32+1));
        __builtin_prefetch(q-(32+1));
    }
    /* do the prefetech as soon as possible, prevent the compiler to
     * reorder the instructions above the prefetch */
    asm volatile("":::"memory");
    c0 = n & 0x1F; /* cache-line is 32 bytes */ // 32字节cache线边界拷贝,这样提升数据搬移速度[luther.gliethttp]
    c1 = n >> 5;
    while ( c1-- ) {
        /* ARMv6 can have up to 3 memory access outstanding */
      __builtin_prefetch(p - (PRELOAD_DISTANCE+1));
      __builtin_prefetch(q - (PRELOAD_DISTANCE+1));
      asm volatile("":::"memory");
      for (i=0 ; i<32 ; i++) {
        *--q = *--p; // 倒着拷贝32字节cache line边界数据,直到对齐
      }
    }
    while ( c0-- ) {
      *--q = *--p; // 开始大批量cache line对齐后数据搬移[luther.gliethttp]
    }
  }

  return dst;
}


static void
fixup_alignment (DBusRealString *real)
{
  unsigned char *aligned;
  unsigned char *real_block;
  unsigned int old_align_offset;

  /* we have to have extra space in real->allocated for the align offset and nul byte */
  _dbus_assert (real->len <= real->allocated - _DBUS_STRING_ALLOCATION_PADDING);
 
  old_align_offset = real->align_offset;
  real_block = real->str - old_align_offset;
 
  aligned = _DBUS_ALIGN_ADDRESS (real_block, 8);

  real->align_offset = aligned - real_block; // 到下一个8字节边界的新offset.[luther.gliethttp]
  real->str = aligned; // 新地址
 
  if (old_align_offset != real->align_offset)
    {
      /* Here comes the suck */
      memmove (real_block + real->align_offset,
               real_block + old_align_offset,
               real->len + 1); // 数据搬移,memmove()函数已经内置解决了数据发生overlap覆盖拷贝问题[luther.gliethttp]
/*
The  memmove()  function  copies  n  bytes from memory area src to memory area dest.  The memory areas may overlap:
copying takes place as though the bytes in src are first copied into a temporary array that does not overlap src or
dest, and the bytes are then copied from the temporary array to dest.
*/
    }

  _dbus_assert (real->align_offset < 8);
  _dbus_assert (_DBUS_ALIGN_ADDRESS (real->str, 8) == real->str);
}

void
_dbus_string_free (DBusString *str)
{
  DBusRealString *real = (DBusRealString*) str;
  DBUS_GENERIC_STRING_PREAMBLE (real);
 
  if (real->constant)
    return;
  dbus_free (real->str - real->align_offset); // 计算出real->str通过malloc申请到的原始地址[luther.gliethttp]

  real->invalid = TRUE;
}
 
阅读(2238) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~