由gcc4.4.6-3编译的jmp到自指令 我有一个C++项目,用GCC-4.1.2-46和GCC-4.4.5-6/P>编译的正确运行
但是当gcc-4.4.6-3使用-O2编译时,它有一个异常死循环 我使用gdb在进程运行时附加它,发现线程正在运行,但堆栈没有改变 objdump程序,发现它有3条指令jmp到self,如下所示:由gcc4.4.6-3编译的jmp到自指令 我有一个C++项目,用GCC-4.1.2-46和GCC-4.4.5-6/P>编译的正确运行,c++,gcc,C++,Gcc,但是当gcc-4.4.6-3使用-O2编译时,它有一个异常死循环 我使用gdb在进程运行时附加它,发现线程正在运行,但堆栈没有改变 objdump程序,发现它有3条指令jmp到self,如下所示: 432f6c: 48 89 c7 mov %rax,%rdi 432f6f: 90 nop 432f70: e8 b3 e4 fd ff callq
432f6c: 48 89 c7 mov %rax,%rdi
432f6f: 90 nop
432f70: e8 b3 e4 fd ff callq 411428 <_Unwind_Resume@plt>
432f75: eb fe jmp 432f75 <_ZN9oceanbase12updateserver11QueryEngine3getERKNS0_5TEKeyE+0x4d5>
432f77: 48 8d 7c 24 70 lea 0x70(%rsp),%rdi
432f7c: 48 89 c3 mov %rax,%rbx
432f7f: e8 9c 32 00 00 callq 436220 <_ZN9oceanbase12updateserver12BitLockGuardD1Ev>
432f6c:48 89 c7 mov%rax,%rdi
432f6f:90无
432f70:e8 b3 e4 fd ff呼叫411428
432f75:eb-fe jmp 432f75
432f77:48 8d 7c 24 70 lea 0x70(%rsp),%rdi
432f7c:48 89 c3 mov%rax,%rbx
432f7f:e8 9c 32 00 00 callq 436220
我没有在代码中使用“goto”
当gcc-4.4.6-3使用-O0编译代码时
jmp到self指令消失了
所以我怀疑它是gcc-4.4.6.3的一个bug
代码是一个简单的多线程Hashmap,使用BitLock保护存储桶:
#define ATOMIC_CAS(val, cmpv, newv) __sync_val_compare_and_swap((val), (cmpv), (newv))
#define ATOMIC_ADD(val, addv) __sync_add_and_fetch((val), (addv))
#define ATOMIC_SUB(val, subv) __sync_sub_and_fetch((val), (subv))
template <typename Key,
typename Value,
typename BucketAllocator,
typename NodeAllocator>
class LightyHashMap
{
struct Node
{
Key key;
Value value;
union
{
Node *next;
int64_t flag;
};
};
static const int64_t EMPTY_FLAG = 0xffffffffffffffff;
static const int64_t INIT_UNIT_SIZE = (64L * 1024L / sizeof(Node)) * sizeof(Node);
typedef Hash<Key> HashFunc;
typedef Equal<Key> EqualFunc;
public:
LightyHashMap(BucketAllocator &bucket_allocator, NodeAllocator &node_allocator);
~LightyHashMap();
private:
DISALLOW_COPY_AND_ASSIGN(LightyHashMap);
public:
int create(const int64_t bucket_num);
void destroy();
int clear();
public:
inline int insert(const Key &key, const Value &value);
inline int get(const Key &key, Value &value);
inline int erase(const Key &key, Value *value = NULL);
inline int64_t uninit_unit_num() const;
inline int64_t bucket_using() const;
inline int64_t size() const;
private:
void init_bucket_unit_(const int64_t bucket_pos);
private:
BucketAllocator &bucket_allocator_;
NodeAllocator &node_allocator_;
int64_t bucket_num_;
Node *buckets_;
volatile int64_t uninit_unit_num_;
uint8_t *init_units_;
BitLock bit_lock_;
int64_t bucket_using_;
int64_t size_;
HashFunc hash_func_;
EqualFunc equal_func_;
};
template <typename Key, typename Value, typename BucketAllocator, typename NodeAllocator>
LightyHashMap<Key, Value, BucketAllocator, NodeAllocator>::LightyHashMap(
BucketAllocator &bucket_allocator,
NodeAllocator &node_allocator) : bucket_allocator_(bucket_allocator),
node_allocator_(node_allocator),
bucket_num_(0),
buckets_(NULL),
uninit_unit_num_(0),
init_units_(NULL),
bucket_using_(0),
size_(0),
hash_func_(),
equal_func_()
{
}
template <typename Key, typename Value, typename BucketAllocator, typename NodeAllocator>
LightyHashMap<Key, Value, BucketAllocator, NodeAllocator>::~LightyHashMap()
{
destroy();
}
template <typename Key, typename Value, typename BucketAllocator, typename NodeAllocator>
int LightyHashMap<Key, Value, BucketAllocator, NodeAllocator>::create(const int64_t bucket_num)
{
int ret = common::OB_SUCCESS;
int64_t uninit_unit_num = (bucket_num * sizeof(Node) / INIT_UNIT_SIZE) \
+ ((0 == (bucket_num * sizeof(Node) % INIT_UNIT_SIZE)) ? 0 : 1);
if (NULL != buckets_)
{
ret = common::OB_INIT_TWICE;
}
else if (0 >= bucket_num)
{
ret = common::OB_INVALID_ARGUMENT;
}
else if (NULL == (buckets_ = (Node*)bucket_allocator_.alloc(bucket_num * sizeof(Node))))
{
ret = common::OB_MEM_OVERFLOW;
}
else if (NULL == (init_units_ = (uint8_t*)bucket_allocator_.alloc(uninit_unit_num * sizeof(uint8_t))))
{
ret = common::OB_MEM_OVERFLOW;
}
else if (OB_SUCCESS != (ret = bit_lock_.init(bucket_num)))
{
// init bit lock fail
}
else
{
bucket_num_ = bucket_num;
uninit_unit_num_ = uninit_unit_num;
memset(init_units_, 0, uninit_unit_num_ * sizeof(uint8_t));
bucket_using_ = 0;
size_ = 0;
}
if (common::OB_SUCCESS != ret)
{
destroy();
}
return ret;
}
template <typename Key, typename Value, typename BucketAllocator, typename NodeAllocator>
void LightyHashMap<Key, Value, BucketAllocator, NodeAllocator>::destroy()
{
if (NULL != buckets_)
{
if (NULL != init_units_)
{
for (int64_t i = 0; i < bucket_num_; i++)
{
int64_t unit_pos = i * sizeof(Node) / INIT_UNIT_SIZE;
uint8_t ov = init_units_[unit_pos];
if (0 == (ov & 0x80))
{
continue;
}
Node *iter = buckets_[i].next;
while (EMPTY_FLAG != buckets_[i].flag
&& NULL != iter)
{
Node *tmp = iter;
iter = iter->next;
node_allocator_.free(tmp);
}
buckets_[i].flag = EMPTY_FLAG;
}
}
bucket_allocator_.free(buckets_);
buckets_ = NULL;
}
if (NULL != init_units_)
{
bucket_allocator_.free(init_units_);
init_units_ = NULL;
}
bit_lock_.destroy();
bucket_num_ = 0;
uninit_unit_num_ = 0;
bucket_using_ = 0;
size_ = 0;
}
template <typename Key, typename Value, typename BucketAllocator, typename NodeAllocator>
int LightyHashMap<Key, Value, BucketAllocator, NodeAllocator>::clear()
{
int ret = common::OB_SUCCESS;
if (NULL == buckets_
|| NULL == init_units_)
{
ret = common::OB_NOT_INIT;
}
else
{
for (int64_t i = 0; i < bucket_num_; i++)
{
int64_t unit_pos = i * sizeof(Node) / INIT_UNIT_SIZE;
uint8_t ov = init_units_[unit_pos];
if (0 == (ov & 0x80))
{
continue;
}
BitLockGuard guard(bit_lock_, i);
Node *iter = buckets_[i].next;
while (EMPTY_FLAG != buckets_[i].flag
&& NULL != iter)
{
Node *tmp = iter;
iter = iter->next;
node_allocator_.free(tmp);
}
buckets_[i].flag = EMPTY_FLAG;
}
uninit_unit_num_ = (bucket_num_ * sizeof(Node) / INIT_UNIT_SIZE) \
+ ((0 == (bucket_num_ * sizeof(Node) % INIT_UNIT_SIZE)) ? 0 : 1);
memset(init_units_, 0, uninit_unit_num_ * sizeof(Node));
bucket_using_ = 0;
size_ = 0;
}
return ret;
}
template <typename Key, typename Value, typename BucketAllocator, typename NodeAllocator>
int LightyHashMap<Key, Value, BucketAllocator, NodeAllocator>::insert(const Key &key, const Value &value)
{
int ret = common::OB_SUCCESS;
if (NULL == buckets_
|| NULL == init_units_)
{
ret = common::OB_NOT_INIT;
}
else
{
int64_t hash_value = hash_func_(key);
int64_t bucket_pos = hash_value % bucket_num_;
init_bucket_unit_(bucket_pos);
BitLockGuard guard(bit_lock_, bucket_pos);
if (EMPTY_FLAG == buckets_[bucket_pos].flag)
{
buckets_[bucket_pos].key = key;
buckets_[bucket_pos].value = value;
buckets_[bucket_pos].next = NULL;
common::atomic_inc((uint64_t*)&bucket_using_);
common::atomic_inc((uint64_t*)&size_);
}
else
{
Node *iter = &(buckets_[bucket_pos]);
while (true)
{
if (equal_func_(iter->key, key))
{
ret = common::OB_ENTRY_EXIST;
break;
}
if (NULL != iter->next)
{
iter = iter->next;
}
else
{
break;
}
}
if (common::OB_SUCCESS == ret)
{
Node *node = (Node*)node_allocator_.alloc(sizeof(Node));
if(NULL == node)
{
ret = common::OB_MEM_OVERFLOW;
}
else
{
node->key = key;
node->value = value;
node->next = NULL;
iter->next = node;
common::atomic_inc((uint64_t*)&size_);
}
}
}
}
return ret;
}
template <typename Key, typename Value, typename BucketAllocator, typename NodeAllocator>
int LightyHashMap<Key, Value, BucketAllocator, NodeAllocator>::get(const Key &key, Value &value)
{
int ret = common::OB_SUCCESS;
if (NULL == buckets_
|| NULL == init_units_)
{
ret = common::OB_NOT_INIT;
}
else
{
int64_t hash_value = hash_func_(key);
int64_t bucket_pos = hash_value % bucket_num_;
init_bucket_unit_(bucket_pos);
BitLockGuard guard(bit_lock_, bucket_pos);
ret = common::OB_ENTRY_NOT_EXIST;
if (EMPTY_FLAG != buckets_[bucket_pos].flag)
{
Node *iter = &(buckets_[bucket_pos]);
while (NULL != iter)
{
if (equal_func_(iter->key, key))
{
value = iter->value;
ret = common::OB_SUCCESS;
break;
}
iter = iter->next;
}
}
}
return ret;
}
template <typename Key, typename Value, typename BucketAllocator, typename NodeAllocator>
int LightyHashMap<Key, Value, BucketAllocator, NodeAllocator>::erase(const Key &key, Value *value)
{
int ret = common::OB_SUCCESS;
if (NULL == buckets_
|| NULL == init_units_)
{
ret = common::OB_NOT_INIT;
}
else
{
int64_t hash_value = hash_func_(key);
int64_t bucket_pos = hash_value % bucket_num_;
init_bucket_unit_(bucket_pos);
BitLockGuard guard(bit_lock_, bucket_pos);
ret = common::OB_ENTRY_NOT_EXIST;
if (EMPTY_FLAG != buckets_[bucket_pos].flag)
{
Node *iter = &(buckets_[bucket_pos]);
Node *prev = NULL;
while (NULL != iter)
{
if (equal_func_(iter->key, key))
{
if (NULL != value)
{
*value = iter->value;
}
if (NULL == prev)
{
buckets_[bucket_pos].flag = EMPTY_FLAG;
}
else
{
// do not free deleted node
prev->next = iter->next;
}
ret = common::OB_SUCCESS;
break;
}
prev = iter;
iter = iter->next;
}
}
}
return ret;
}
template <typename Key, typename Value, typename BucketAllocator, typename NodeAllocator>
int64_t LightyHashMap<Key, Value, BucketAllocator, NodeAllocator>::uninit_unit_num() const
{
return uninit_unit_num_;
}
template <typename Key, typename Value, typename BucketAllocator, typename NodeAllocator>
int64_t LightyHashMap<Key, Value, BucketAllocator, NodeAllocator>::bucket_using() const
{
return bucket_using_;
}
template <typename Key, typename Value, typename BucketAllocator, typename NodeAllocator>
int64_t LightyHashMap<Key, Value, BucketAllocator, NodeAllocator>::size() const
{
return size_;
}
template <typename Key, typename Value, typename BucketAllocator, typename NodeAllocator>
void LightyHashMap<Key, Value, BucketAllocator, NodeAllocator>::init_bucket_unit_(const int64_t bucket_pos)
{
while (0 < uninit_unit_num_)
{
int64_t unit_pos = bucket_pos * sizeof(Node) / INIT_UNIT_SIZE;
uint8_t ov = init_units_[unit_pos];
if (ov & 0x80)
{
break;
}
ov = 0;
uint8_t nv = ov | 0x01;
if (ov == ATOMIC_CAS(&(init_units_[unit_pos]), ov, nv))
{
int64_t ms_size = std::min((bucket_num_ - bucket_pos) * sizeof(Node), (uint64_t)INIT_UNIT_SIZE);
memset((char*)buckets_ + unit_pos * INIT_UNIT_SIZE, -1, ms_size);
ATOMIC_SUB(&uninit_unit_num_, 1);
init_units_[unit_pos] = 0x80;
break;
}
}
}
#定义原子CA(val,cmpv,newv)(同步)(val)(cmpv)(newv)(val)(cmpv))
#定义原子添加(val,addv)\同步添加和获取((val),(addv))
#定义原子_SUB(val,subv)__sync_SUB_和_fetch((val),(subv))
模板
类光照图
{
结构体类型
{
钥匙;
价值观;
联盟
{
节点*下一步;
int64_t标志;
};
};
静态常量int64\u t EMPTY\u标志=0xFFFFFFFFFFFFFF;
静态常量int64_t INIT_UNIT_SIZE=(64L*1024L/sizeof(节点))*sizeof(节点);
typedef散列HashFunc;
typedef等于等分;
公众:
LightyHashMap(BucketAllocator和bucket_分配器、NodeAllocator和node_分配器);
~LightyHashMap();
私人:
不允许复制和分配(LightyHashMap);
公众:
int create(const int64_t bucket_num);
无效销毁();
int clear();
公众:
内联整数插入(常量键和键、常量值和值);
内联int get(常量键和键、值和值);
内联整数擦除(常量键和键,值*Value=NULL);
内联int64\u t uninit\u unit\u num()常量;
使用()常量内联int64_t bucket_;
内联int64_t size()常量;
私人:
void init_bucket_unit_(const int64_t bucket_pos);
私人:
BucketAllocator和bucket分配器;
节点定位器和节点分配器;
int64_t bucket_num_;
节点*buckets;
易失性int64\u t uninit\u unit\u num;
uint8_t*初始单位;
比特锁比特锁;
int64_t bucket_使用_;
int64_t size_;
HashFunc hash_func;
相等函数相等函数;
};
模板
LightyHashMap::LightyHashMap(
BucketAllocator和bucket_分配器,
节点定位器和节点分配器):桶分配器(桶分配器),
节点分配器(节点分配器),
桶数(0),
(空),
取消单位数量(0),
初始单位(空),
铲斗_使用_u0,
尺寸(0),
hash_func_(),
相等函数
{
}
模板
LightyHashMap::~LightyHashMap()
{
破坏();
}
模板
int LightyHashMap::create(const int64_t bucket_num)
{
int-ret=common::OB_SUCCESS;
int64\u t uninit\u unit\u num=(bucket\u num*sizeof(Node)/INIT\u unit\u SIZE)\
+((0==(bucket_num*sizeof(Node)%INIT_UNIT_SIZE))?0:1);
如果(空!=桶)
{
ret=common::OB_INIT_两次;
}
如果(0>=bucket\u num),则为else
{
ret=common::OB_无效_参数;
}
else if(NULL==(bucket.=(Node*)bucket.\u分配器..alloc(bucket.\u num*sizeof(Node)))
{
ret=公共::OB_MEM_溢出;
}
else if(NULL==(初始单位=(uint8\u t*)桶分配程序分配(uninit\u单位数量*sizeof(uint8\u t)))
{
ret=公共::OB_MEM_溢出;
}
else if(OB_SUCCESS!=(ret=bit_lock.init(bucket_num)))
{
//初始位锁定失败
}
其他的
{
bucket_num=bucket_num;
uninit\u unit\u num=uninit\u unit\u num;
memset(init_units,0,uninit_unit_num_*sizeof(uint8_t));
桶_使用_u=0;
尺寸=0;
}
if(common::OB_SUCCESS!=ret)
{
破坏();
}
返回ret;
}
模板
void LightyHashMap::destroy()
{
如果(空!=桶)
{
如果(NULL!=初始单位)
{
对于(int64\u t i=0;inext;
节点分配程序空闲(tmp);
}
bucket_u[i].flag=空_u标志;
}
}
桶分配程序空闲(桶);
bucket=NULL;
}
如果(NULL!=初始单位)
{
桶分配程序空闲(初始单位);
初始单位=空;
}
B
static const uint8_t BIT_MASKS[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
class BitLock
{
public:
BitLock() : size_(0),
bits_(NULL)
{
};
~BitLock()
{
destroy();
};
public:
inline int init(const int64_t size);
inline void destroy();
inline int lock(const int64_t index);
inline int unlock(const int64_t index);
private:
int64_t size_;
uint8_t *bits_;
};
class BitLockGuard
{
public:
BitLockGuard(BitLock &lock, const int64_t index) : lock_(lock),
index_(index)
{
lock_.lock(index_);
};
~BitLockGuard()
{
lock_.unlock(index_);
};
private:
BitLock &lock_;
const int64_t index_;
};
int BitLock::init(const int64_t size)
{
int ret = common::OB_SUCCESS;
if (0 < size_
|| NULL != bits_)
{
ret = common::OB_INIT_TWICE;
}
else if (0 >= size)
{
ret = common::OB_INVALID_ARGUMENT;
}
else
{
int64_t byte_size = common::upper_align(size, 8) / 8;
if (NULL == (bits_ = (uint8_t*)common::ob_malloc(byte_size)))
{
ret = common::OB_MEM_OVERFLOW;
}
else
{
memset(bits_, 0, byte_size);
size_ = size;
}
}
return ret;
}
void BitLock::destroy()
{
if (NULL != bits_)
{
common::ob_free(bits_);
bits_ = NULL;
}
size_ = 0;
}
int BitLock::lock(const int64_t index)
{
int ret = common::OB_SUCCESS;
if (0 >= size_
|| NULL == bits_)
{
ret = common::OB_NOT_INIT;
}
else if (index >= size_)
{
ret = common::OB_INVALID_ARGUMENT;
}
else
{
int64_t byte_index = index / 8;
int64_t bit_index = index % 8;
while (true)
{
uint8_t ov = bits_[byte_index];
if (ov & BIT_MASKS[bit_index])
{
continue;
}
if (ov == ATOMIC_CAS(&(bits_[byte_index]), ov, ov | BIT_MASKS[bit_index]))
{
break;
}
}
}
return ret;
}
int BitLock::unlock(const int64_t index)
{
int ret = common::OB_SUCCESS;
if (0 >= size_
|| NULL == bits_)
{
ret = common::OB_NOT_INIT;
}
else if (index >= size_)
{
ret = common::OB_INVALID_ARGUMENT;
}
else
{
int64_t byte_index = index / 8;
int64_t bit_index = index % 8;
while (true)
{
uint8_t ov = bits_[byte_index];
if (!(ov & BIT_MASKS[bit_index]))
{
// have not locked
break;
}
if (ov == ATOMIC_CAS(&(bits_[byte_index]), ov, ov & ~BIT_MASKS[bit_index]))
{
break;
}
}
}
return ret;
}
while (true)
{
uint8_t ov = bits_[byte_index];
if (ov & BIT_MASKS[bit_index])
{
continue;
}
if (ov == ATOMIC_CAS(&(bits_[byte_index]), ov, ov | BIT_MASKS[bit_index]))
{
break;
}
}
while (true)
{
uint8_t ov = bits_[byte_index];
if (ov & BIT_MASKS[bit_index])
{
__sync_synchronize(); // or define ATOMIC_SYNC if you prefer
continue;
}
if (ov == ATOMIC_CAS(&(bits_[byte_index]), ov, ov | BIT_MASKS[bit_index]))
{
break;
}
}