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);