bit位快速查询asm实现(find_next_zero_bit)

最近在重翻些FS的代码,file open的时候首先要获取unused fd, 例如如下:

/*
 * Find an empty file descriptor entry, and mark it busy.
 */
int get_unused_fd(void)
{
 struct files_struct * files = current->files;
 int fd, error;

   error = -EMFILE;
 write_lock(&files->file_lock);

repeat:
  fd = find_next_zero_bit(files->open_fds,
    files->max_fdset,
    files->next_fd);

........................

 

 这里重点研究下find_next_zero_bit,这里是从open_fds中找到空隙的fd,翻开这块内部代码:

先温习下这里的几个重点asm命令(intel):

bsfl:

      bsfl source, destination

     从右向左(0->15,31位)在source中找到非0的位置,并保存在destination

scasl:

     扫描EDI(隐含源)和EAX的匹配度,和repe,repne结合

     比如 repe; scasl;

     含义:如果EDI和EAX等值,继续loop, until到不匹配

 

static __inline__ int find_next_zero_bit (void * addr, int size, int offset)
{
 unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
 int set = 0, bit = offset & 31, res;
 
 if (bit) {
  /*
   * Look for zero in first byte
   */
  __asm__(

   //从offset开始的INT查找bit 1,

   "bsfl %1,%0/n/t"
   "jne 1f/n/t"
   "movl $32, %0/n"
   "1:"
   : "=r" (set)

   // 注意取反,目标是look zero,
   : "r" (~(*p >> bit)));
  if (set < (32 - bit))
   return set + offset;
  set = 32 - bit;
  p++;
 }
 /*
  * No zero yet, search remaining full bytes for a zero
  */
 res = find_first_zero_bit (p, size - 32 * (p - (unsigned long *) addr));
 return (offset + set + res);
}

 

 

/*
 * Find-bit routines..
 */
static __inline__ int find_first_zero_bit(void * addr, unsigned size)
{
 int d0, d1, d2;
 int res;

 if (!size)
  return 0;
 /* This looks at memory. Mark it volatile to tell gcc not to move it around */
 __asm__ __volatile__(

 // EAX赋值0xFFFFFFFF
  "movl $-1,%%eax/n/t"

 // EDX复制全0,xorl这种比movl要快
  "xorl %%edx,%%edx/n/t"

 // EDI也就是addr开始的源
  "repe; scasl/n/t"

 //如果没找到
  "je 1f/n/t"

 //找到,继续,首先把EAX的前部分设置0
  "xorl -4(%%edi),%%eax/n/t"
  "subl $4,%%edi/n/t"

  //从EAX查找bit 1的位置,由于刚才xorl,这里的bit 1也就是我们希望的bit 0
  "bsfl %%eax,%%edx/n"

  // EDI-ADDR,得到偏移(单位是:字节)
  "1:/tsubl %%ebx,%%edi/n/t"

  //从字节换算成bit位
  "shll $3,%%edi/n/t"  
  "addl %%edi,%%edx"
  :"=d" (res), "=&c" (d0), "=&D" (d1), "=&a" (d2)
  :"1" ((size + 31) >> 5), "2" (addr), "b" (addr));
 return res;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值