pthread_cond_timedwait returns FreeBSD 中的 EPERM
pthread_cond_timedwait returns EPERM in FreeBSD
我有一个可在其他 Linux 平台上运行的代码库,例如 CentOS、Redhat...
但它在我的 FreeBSD 10.1 发行版中失败了。
我这里有一个监视器处理程序,它每 10 秒执行一次相同的操作。
前几次正常,return60(超时)所以monitor_handler保持运行ning。但是当它 return 1 (Operation not permitted) 时,处理程序将停止并锁定在 pthread_mutex_lock.
我尝试删除 getOSName() 并只从处理程序打印一些值,处理程序可以保持 运行ning。不过不知道是不是时间问题,可能再过几天就失效了。
我也尝试不在 getOSName() 中使用 popen,它可能 运行 更长但仍然会挂起。但是 ret 是 60(超时)并在 pthread_mutex_lock.
之后挂起
有人知道这三种情况吗? FreeBSD 中是否存在此功能的错误,或者我不能这样使用它。
有没有其他方法可以在 FreeBSD 中实现等待和锁定?
谢谢。
=========更新重现的完整代码====================
pthread_t monitor_thread;
pthread_mutex_t monitor_lock;
pthread_cond_t monitor_condition;
int start() {
if (getServiceCount() > 0) {
printf("service existed\n");
printErrLog(" ", "service existed");
return EXIT_FAILURE;
}
if (initIni() == EXIT_FAILURE)
exit(EXIT_FAILURE);
struct sigaction act;
//signal terminate call back
memset(&act, '[=12=]', sizeof(act));
act.sa_sigaction = &signal_callback_handler;
act.sa_flags = SA_SIGINFO;
sigaction(SIGTERM, &act, NULL);
skeleton_daemon();
_init_mutex();
mStatus = 1;
getTASInfo();
if (initThread() == EXIT_FAILURE)
exit(EXIT_FAILURE);
return EXIT_SUCCESS;
}
void skeleton_daemon() {
pid_t pid;
pid = fork();
if (pid < 0) {
printf("fork failed!\n");
exit(EXIT_FAILURE);
}
//printf("file name %s\n", pidFile);
if (pid > 0) {
//printf("pid = %d\n", pid);
exit(EXIT_SUCCESS);
}
umask(0);
if (setsid() < 0) {
printf("set sid failed!\n");
exit(EXIT_FAILURE);
}
if (chdir("/") < 0) {
printf("change to root directory failed!\n");
exit(EXIT_FAILURE);
}
int x;
for (x = sysconf(_SC_OPEN_MAX); x > 0; x--) {
close(x);
}
}
int initThread() {
int err;
if (pthread_mutex_init(&monitor_lock, NULL) != 0) {
printf("\n mutex init failed\n");
printErrLog("initThread ", "monitor mutex init failed");
return(EXIT_FAILURE);
}
if (pthread_cond_init(&monitor_condition, NULL) != 0) {
printf("\n condition init failed\n");
printErrLog("initThread ", "monitor condition init failed");
return(EXIT_FAILURE);
}
err = pthread_create(&monitor_thread, NULL, (void *)&monitor_handler, NULL);
if (err != 0) {
printErrLog("pthread_create ", " monitor thread create failed");
return(EXIT_FAILURE);
}
closelog();
pthread_join(monitor_thread, NULL);
return(EXIT_SUCCESS);
}
int initIni() {
config_init(&cfg);
/* Read the file. If there is an error, report it and exit. */
if (!config_read_file(&cfg, ini_file)) {
root = config_root_setting(&cfg);
/* Add some settings to the configuration. */
group = config_setting_add(root, PATH_SEC, CONFIG_TYPE_GROUP);
setting = config_setting_add(group, INSTALLED_PATH_KEY, CONFIG_TYPE_STRING);
config_setting_set_string(setting, installed_path);
setting = config_setting_add(group, LOG_PATH_KEY, CONFIG_TYPE_STRING);
config_setting_set_string(setting, log_file);
setting = config_setting_add(group, ERR_LOG_PATH_KEY, CONFIG_TYPE_STRING);
config_setting_set_string(setting, err_log_file);
setting = config_setting_add(group, COMMAND_LOG_PATH_KEY, CONFIG_TYPE_STRING);
config_setting_set_string(setting, command_log_file);
group = config_setting_add(root, CONFIG_SEC, CONFIG_TYPE_GROUP);
setting = config_setting_add(group, UPDATE_FREQ_KEY, CONFIG_TYPE_INT);
config_setting_set_int(setting, DEFAULT_FREQ);
/* Write out the new configuration. */
if (!config_write_file(&cfg, ini_file))
{
fprintf(stderr, "Error while writing file.\n");
printErrLog("initIni ", "Error while writing file");
config_destroy(&cfg);
return(EXIT_FAILURE);
}
}
else {
config_setting_t *s = config_lookup(&cfg, CONFIG_SEC);
config_setting_lookup_int(s, UPDATE_FREQ_KEY, &updateSec);
}
if (updateSec < MIN_FREQ)
updateSec = MIN_FREQ;
else if (updateSec > MAX_FREQ)
updateSec = MAX_FREQ;
config_destroy(&cfg);
return(EXIT_SUCCESS);
}
void printLog(BYTE * title, BYTE * value) {
FILE *fp = NULL;
fp = fopen(log_file, "a+");
fprintf(fp, "%s %s\n", title, value);
fflush(fp);
fclose(fp);
}
void printIntLog(BYTE * title, int value) {
FILE *fp = NULL;
fp = fopen(log_file, "a+");
fprintf(fp, "%s %d\n", title, value);
fflush(fp);
fclose(fp);
}
void getStartTime() {
FILE *fp = NULL;
fp = fopen(time_file, "r");
memset(mTimeStamp, '[=12=]', sizeof(mTimeStamp));
fgets(mTimeStamp, 5, fp);
fclose(fp);
}
int getTASInfo() {
BYTE *information = NULL;
BYTE *information2 = NULL;
asprintf(&information, "%s%s%s%s%s%s%d%s%s%s", VERSION, ";", BUILD, ";", PROTOCOL_VERSION, ";",
mStatus, ";", mTimeStamp, ";");
asprintf(&information2, "%s%s%s%s%s%s%d%s%x%x%x%x%s", VERSION, ";", BUILD, ";", PROTOCOL_VERSION, ";",
mStatus, ";", mTimeStamp[0], mTimeStamp[1], mTimeStamp[2], mTimeStamp[3],";");
printLog("TAS info ->", information2);
return 0;
}
int getOSName() {
FILE *fp = NULL;
BYTE buffer[BUFFER_SIZE];
BYTE *tmp = NULL;
TRY {
if ((fp = popen("uname", "r")) == NULL) {
THROW (CMD_NOT_FND);
}
else {
if (fgets(buffer, sizeof(buffer), fp) == NULL)
THROW (CMD_NOT_FND);
}
}
CATCH (CMD_NOT_FND) {
buffer[0] = 'n';
buffer[1] = '/';
buffer[2] = 'a';
buffer[3] = '[=12=]';
printErrLog("OS name ->", "command not found");
}
FINALLY {
pclose(fp);
//printf("OS name length %d\n", strlen(buffer));
}
ETRY;
tmp = strrchr(buffer, '\n');
if (tmp)
*tmp = ';';
printf("OS name : %s\n", buffer);
printLog("OS name ->", buffer);
return 0;
}
void signal_callback_handler(int signum, siginfo_t *siginfo, void *context) {
if (signum == SIGTERM) {
clearData();
}
exit(signum);
}
void monitor_handler(void *arg) {
static_flag = 1;
struct timespec outtime;
struct timeval now;
int ret = 0;
pthread_mutex_lock(&monitor_lock);
while (!getStopFlag()) {
getOSName();
gettimeofday(&now, NULL);
outtime.tv_sec = now.tv_sec + updateSec;
outtime.tv_nsec = now.tv_usec * 1000;
ret = pthread_cond_timedwait(&monitor_condition, &monitor_lock, &outtime);
}
pthread_mutex_unlock(&monitor_lock);
pthread_exit(0);
}
我找到了解决方案
for (x = sysconf(_SC_OPEN_MAX); x > 0; x--) {
close(x);
}
以上代码是系统出问题的地方,在FreeBSD下不能使用。
你需要像下面这样写
/* close all descriptors */
for (i = getdtablesize(); i >= 0; --i)
{
close(i);
}
/* Route I/O connections */
/* Open STDIN */
i = open("/dev/null", O_RDWR);
/* STDOUT */
dup(i);
/* STDERR */
dup(i);
我有一个可在其他 Linux 平台上运行的代码库,例如 CentOS、Redhat... 但它在我的 FreeBSD 10.1 发行版中失败了。 我这里有一个监视器处理程序,它每 10 秒执行一次相同的操作。
前几次正常,return60(超时)所以monitor_handler保持运行ning。但是当它 return 1 (Operation not permitted) 时,处理程序将停止并锁定在 pthread_mutex_lock.
我尝试删除 getOSName() 并只从处理程序打印一些值,处理程序可以保持 运行ning。不过不知道是不是时间问题,可能再过几天就失效了。
我也尝试不在 getOSName() 中使用 popen,它可能 运行 更长但仍然会挂起。但是 ret 是 60(超时)并在 pthread_mutex_lock.
之后挂起有人知道这三种情况吗? FreeBSD 中是否存在此功能的错误,或者我不能这样使用它。 有没有其他方法可以在 FreeBSD 中实现等待和锁定?
谢谢。
=========更新重现的完整代码====================
pthread_t monitor_thread;
pthread_mutex_t monitor_lock;
pthread_cond_t monitor_condition;
int start() {
if (getServiceCount() > 0) {
printf("service existed\n");
printErrLog(" ", "service existed");
return EXIT_FAILURE;
}
if (initIni() == EXIT_FAILURE)
exit(EXIT_FAILURE);
struct sigaction act;
//signal terminate call back
memset(&act, '[=12=]', sizeof(act));
act.sa_sigaction = &signal_callback_handler;
act.sa_flags = SA_SIGINFO;
sigaction(SIGTERM, &act, NULL);
skeleton_daemon();
_init_mutex();
mStatus = 1;
getTASInfo();
if (initThread() == EXIT_FAILURE)
exit(EXIT_FAILURE);
return EXIT_SUCCESS;
}
void skeleton_daemon() {
pid_t pid;
pid = fork();
if (pid < 0) {
printf("fork failed!\n");
exit(EXIT_FAILURE);
}
//printf("file name %s\n", pidFile);
if (pid > 0) {
//printf("pid = %d\n", pid);
exit(EXIT_SUCCESS);
}
umask(0);
if (setsid() < 0) {
printf("set sid failed!\n");
exit(EXIT_FAILURE);
}
if (chdir("/") < 0) {
printf("change to root directory failed!\n");
exit(EXIT_FAILURE);
}
int x;
for (x = sysconf(_SC_OPEN_MAX); x > 0; x--) {
close(x);
}
}
int initThread() {
int err;
if (pthread_mutex_init(&monitor_lock, NULL) != 0) {
printf("\n mutex init failed\n");
printErrLog("initThread ", "monitor mutex init failed");
return(EXIT_FAILURE);
}
if (pthread_cond_init(&monitor_condition, NULL) != 0) {
printf("\n condition init failed\n");
printErrLog("initThread ", "monitor condition init failed");
return(EXIT_FAILURE);
}
err = pthread_create(&monitor_thread, NULL, (void *)&monitor_handler, NULL);
if (err != 0) {
printErrLog("pthread_create ", " monitor thread create failed");
return(EXIT_FAILURE);
}
closelog();
pthread_join(monitor_thread, NULL);
return(EXIT_SUCCESS);
}
int initIni() {
config_init(&cfg);
/* Read the file. If there is an error, report it and exit. */
if (!config_read_file(&cfg, ini_file)) {
root = config_root_setting(&cfg);
/* Add some settings to the configuration. */
group = config_setting_add(root, PATH_SEC, CONFIG_TYPE_GROUP);
setting = config_setting_add(group, INSTALLED_PATH_KEY, CONFIG_TYPE_STRING);
config_setting_set_string(setting, installed_path);
setting = config_setting_add(group, LOG_PATH_KEY, CONFIG_TYPE_STRING);
config_setting_set_string(setting, log_file);
setting = config_setting_add(group, ERR_LOG_PATH_KEY, CONFIG_TYPE_STRING);
config_setting_set_string(setting, err_log_file);
setting = config_setting_add(group, COMMAND_LOG_PATH_KEY, CONFIG_TYPE_STRING);
config_setting_set_string(setting, command_log_file);
group = config_setting_add(root, CONFIG_SEC, CONFIG_TYPE_GROUP);
setting = config_setting_add(group, UPDATE_FREQ_KEY, CONFIG_TYPE_INT);
config_setting_set_int(setting, DEFAULT_FREQ);
/* Write out the new configuration. */
if (!config_write_file(&cfg, ini_file))
{
fprintf(stderr, "Error while writing file.\n");
printErrLog("initIni ", "Error while writing file");
config_destroy(&cfg);
return(EXIT_FAILURE);
}
}
else {
config_setting_t *s = config_lookup(&cfg, CONFIG_SEC);
config_setting_lookup_int(s, UPDATE_FREQ_KEY, &updateSec);
}
if (updateSec < MIN_FREQ)
updateSec = MIN_FREQ;
else if (updateSec > MAX_FREQ)
updateSec = MAX_FREQ;
config_destroy(&cfg);
return(EXIT_SUCCESS);
}
void printLog(BYTE * title, BYTE * value) {
FILE *fp = NULL;
fp = fopen(log_file, "a+");
fprintf(fp, "%s %s\n", title, value);
fflush(fp);
fclose(fp);
}
void printIntLog(BYTE * title, int value) {
FILE *fp = NULL;
fp = fopen(log_file, "a+");
fprintf(fp, "%s %d\n", title, value);
fflush(fp);
fclose(fp);
}
void getStartTime() {
FILE *fp = NULL;
fp = fopen(time_file, "r");
memset(mTimeStamp, '[=12=]', sizeof(mTimeStamp));
fgets(mTimeStamp, 5, fp);
fclose(fp);
}
int getTASInfo() {
BYTE *information = NULL;
BYTE *information2 = NULL;
asprintf(&information, "%s%s%s%s%s%s%d%s%s%s", VERSION, ";", BUILD, ";", PROTOCOL_VERSION, ";",
mStatus, ";", mTimeStamp, ";");
asprintf(&information2, "%s%s%s%s%s%s%d%s%x%x%x%x%s", VERSION, ";", BUILD, ";", PROTOCOL_VERSION, ";",
mStatus, ";", mTimeStamp[0], mTimeStamp[1], mTimeStamp[2], mTimeStamp[3],";");
printLog("TAS info ->", information2);
return 0;
}
int getOSName() {
FILE *fp = NULL;
BYTE buffer[BUFFER_SIZE];
BYTE *tmp = NULL;
TRY {
if ((fp = popen("uname", "r")) == NULL) {
THROW (CMD_NOT_FND);
}
else {
if (fgets(buffer, sizeof(buffer), fp) == NULL)
THROW (CMD_NOT_FND);
}
}
CATCH (CMD_NOT_FND) {
buffer[0] = 'n';
buffer[1] = '/';
buffer[2] = 'a';
buffer[3] = '[=12=]';
printErrLog("OS name ->", "command not found");
}
FINALLY {
pclose(fp);
//printf("OS name length %d\n", strlen(buffer));
}
ETRY;
tmp = strrchr(buffer, '\n');
if (tmp)
*tmp = ';';
printf("OS name : %s\n", buffer);
printLog("OS name ->", buffer);
return 0;
}
void signal_callback_handler(int signum, siginfo_t *siginfo, void *context) {
if (signum == SIGTERM) {
clearData();
}
exit(signum);
}
void monitor_handler(void *arg) {
static_flag = 1;
struct timespec outtime;
struct timeval now;
int ret = 0;
pthread_mutex_lock(&monitor_lock);
while (!getStopFlag()) {
getOSName();
gettimeofday(&now, NULL);
outtime.tv_sec = now.tv_sec + updateSec;
outtime.tv_nsec = now.tv_usec * 1000;
ret = pthread_cond_timedwait(&monitor_condition, &monitor_lock, &outtime);
}
pthread_mutex_unlock(&monitor_lock);
pthread_exit(0);
}
我找到了解决方案
for (x = sysconf(_SC_OPEN_MAX); x > 0; x--) {
close(x);
}
以上代码是系统出问题的地方,在FreeBSD下不能使用。 你需要像下面这样写
/* close all descriptors */
for (i = getdtablesize(); i >= 0; --i)
{
close(i);
}
/* Route I/O connections */
/* Open STDIN */
i = open("/dev/null", O_RDWR);
/* STDOUT */
dup(i);
/* STDERR */
dup(i);