最近在移植和测试syslogd代码时,碰到两个问题:Resource temporarily unavailable(EAGAIN)和 Numerical result out of range。
移植的时候,在初始化全局变量的时候,有sembuf的初始化。如下图
struct sembuf SMwup[1] = = { {1, -1, IPC_NOWAIT} }; //此部分对应V操作
struct sembuf SMwdn[3] == { {0, 0}, {1, 0}, {1, +1} };//此部分对应P操作。
开始看到这部分代码,发现V操作的sem_flag设置为IPC_NOWAIT。我就想当然的设置将P操作初始化为如下:
struct sembuf SMwdn[3] == { {0, 0,IPC_NOWAIT}, {1, 0,IPC_NOWAIT}, {1, +1,IPC_NOWAIT} };
结果在测试的过程中发现,程序运行一段时间,当有很多进程同时写syslogd时,syslogd就报如下的问题。
1、Resource temporarily unavailable(EAGAIN)问题。
从网上查看semop函数使用发现,当执行P操作时,如果对应的sem_flag设置为IPC_NOWAIT时,就会很容易出现此问题,原因是当多个进程同时写syslogd时,如果已经有进程写syslogd,此时此进程就占用了信号量,其他进程再来对此信号量执行P操作时,由于设置了IPC_NOWAIT,后进入的进程不会等待,只会立即返回,同时报Resource temporarily unavailable(
EAGAIN)错误。
在网上查看的过程中发现,sem_flag还有一个SEM_UNDO标志,使用此标志,当进程退出时,系统会负责回收信号量资源。我考虑到syslogd进程需要重启,就设置了此标志。此时的sembuf初始化如下:
struct sembuf SMwdn[3] == { {0, 0,SEM_UNDO}, {1, 0,SEM_UNDO}, {1, +1,SEM_UNDO} };
修改后初步测试几把,没有出现此问题。以为修改成功。但是在后续的测试过程中,出现了如下的问题。
2、Numerical result out of range
从网上查找相同的问题,发现也有人遇到此问题。有的人是说不设置sem_flag,使用默认的0值。回想发现,syslogd原始代码就是这样的。另外也有人说设置sem_flag时,P和V操作都需要设置SEM_UNDO。考虑需要系统恢复信号量,使用第二种方式。此时P和V操作对应的sembuf设置如下:
struct sembuf SMwup[1] = = { {1, -1, IPC_NOWAIT|SEM_UNDO
} }; //此部分对应V操作
struct sembuf SMwdn[3] == { {0, 0}, {1, 0}, {1, +1,SEM_UNDO } };//此部分对应P操作
struct sembuf SMwdn[3] == { {0, 0}, {1, 0}, {1, +1,SEM_UNDO } };//此部分对应P操作
修改后反复测试代码,设置不同的日志等级测试均没有出现上面的问题。