假设在32位arm平台的一个移位操作
int bit = 1<<30;
这是合法的。
那么平台换成了64位arm,
int bit = 1 << 34;
合法吗,显然不合法,因为int的长度就是32 比特,不管32位arm还是64位arm上。要移动34位显然超出了它的表示范围。
我们知道在aarch64架构下,long是64位的,那么改成:
long bit = 1 << 34 合法吗。并不。因为这里的1 其实是个int型,默认的嘛。长度仍然是32位!所以对一个32位的int型移位34 显然也不合法。
那么只有改成:
long bit = (long)1 << 34
才是正确的。
这个BUG始于这几天调试的goahead。平台是aarch64 海思。
一旦创建了很多VPSS,也就是创建了很多文件描述符,那么goahead监听的文件描述符就可能很大,goahead做select掩码的时候,不仅仅掩码类型是int,连特么移位的1 也是保持默认的int型。这样整个goahead服务已启动就会不停的select退出,这个服务沙雕。
贴出原有代码:
PUBLIC int socketSelect(int sid, int timeout)
{
WebsSocket *sp;
struct timeval tv;
fd_mask *readFds, *writeFds, *exceptFds;
int all, len, nwords, index, bit, nEvents;
/*
Allocate and zero the select masks
*/
nwords = (socketHighestFd + NFDBITS) / NFDBITS;
len = nwords * sizeof(fd_mask);
readFds = walloc(len);
memset(readFds, 0, len);
writeFds = walloc(len);
memset(writeFds, 0, len);
exceptFds = walloc(len);
memset(exceptFds, 0, len);
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
/*
Set the select event masks for events to watch
*/
all = nEvents = 0;
if (sid < 0) {
all++;
sid = 0;
}
for (; sid < socketMax; sid++) {
if ((sp = socketList[sid]) == NULL) {
if (all == 0) {
break;
} else {
continue;
}
}
assert(sp);
/*
Initialize the ready masks and compute the mask offsets.
*/
index = sp->sock / (NBBY * sizeof(fd_mask));
bit = 1 << (sp->sock % (NBBY * sizeof(fd_mask)));
if (sp->handlerMask & SOCKET_READABLE) {
readFds[index] |= bit;
}
if (sp->handlerMask & SOCKET_WRITABLE) {
writeFds[index] |= bit;
}
if (sp->handlerMask & SOCKET_EXCEPTION) {
exceptFds[index] |= bit;
}
if (sp->flags & SOCKET_RESERVICE) {
tv.tv_sec = 0;
tv.tv_usec = 0;
}
.................................
注意看加粗部分。bit用于计算掩码位,index用于计算字节数。aarch64上NBBY 和
sizeof(fd_mask)都是8.可见这里bit计算必定会出篓子,自己是int型,用于移位的1也是默认的int.
那么如何修改呢?简单,把bit设为long, 1 也强制转换成long 就行了。:
long all, len, nwords, index, bit, nEvents;
....
index = sp->sock / (NBBY * sizeof(fd_mask));
bit = (long)1 << (sp->sock % (NBBY * sizeof(fd_mask)));
这样就解决了。