C - 长时间运行的 while 循环出现段错误

标签 c while-loop rotation segmentation-fault

我使用内置运动传感器(由硬盘主动保护系统使用)或通过按钮手动在 Thinkpad X41 可转换笔记本电脑上编写了用于旋转屏幕的小守护程序。程序运行得很好,但一段时间后(5 到 15 分钟)会因段错误而崩溃。

我知道互联网上有很多用 bash 或 python 编写的脚本可以做到这一点,但它们都不适合我的需求和愿景,程序应该如何工作。 我知道,例如提到的 bash 可能对此更好,但与 C 相比,我对它的经验为零,在 C 中,我至少从一些高中类(class)中获得了最少的基本经验,所以我选择了它。

这是代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#define TRUE 1
#define FALSE 0
#define NIL -1

#define XRANDR_GREP_COMMAND "xrandr -q --verbose|grep LVDS1|cut -b37-37"
#define DAEMON_LOCK_FILE "/dev/shm/thinkrotate.lock"
#define DAEMON_STATE_FILE "/dev/shm/thinkrotate.st"
#define SWIVEL_STATE_FILE "/sys/devices/platform/thinkpad_acpi/hotkey_tablet_mode"
#define GYRO_STATE_FILE "/sys/devices/platform/hdaps/position"

#define BUBBLE_TERMINATED "notify-send 'Ukončenie programu' 'ThinkRotate démon dostal príkaz na ukončenie'"
#define BUBBLE_SWIVEL_DOWN "notify-send 'Notebook v tablet móde' 'Veko bolo sklopené, aktivovaná automatická rotácia'"
#define BUBBLE_SWIVEL_UP "notify-send 'Notebook v štandartnom režime' 'Rotácia je deaktivovaná'"
#define BUBBLE_RETURN_POSITION "notify-send 'Automatická rotácia zapnutá' 'Pre vypnutie automatickej rotácie obrazu stlačte tlačítko rotácie.'"
#define BUBBLE_START_MANUAL_ROTATION "notify-send 'Automatická rotácia vypnutá' 'Rotácia bude zapnutá znovu až pri návrate do tejto polohy, dovtedy na otáčanie obrazu používajte tlačidlo.'"

#define SWIVEL_DOWN_COMMANDS ""
#define SWIVEL_UP_COMMANDS ""
#define WIDTH_COMMANDS ""
#define HEIGHT_COMMANDS ""

int get_lock(void) {
    int fdlock;
    struct flock fl;
    fl.l_type = F_WRLCK;
    fl.l_whence = SEEK_SET;
    fl.l_start = 0;
    fl.l_len = 1;
    if((fdlock = open(DAEMON_LOCK_FILE, O_WRONLY|O_CREAT, 0666)) == -1) { return 0; }
    if(fcntl(fdlock, F_SETLK, &fl) == -1) { return 0; }
    return 1;
}

int next_rotation(int direction) {
    int next;
    int pos;
    pos = current_pos();
    if (direction == 1) {
        switch (pos) {
            case 0:
                next = 1;
            break;
            case 1:
                next = 2;
            break;
            case 2:
                next = 3;
            break;
            case 3:
                next = 0;
            break;
        }
    } else if (direction == 2) {
        switch (pos) {
            case 0:
                next = 3;
            break;
            case 1:
                next = 0;
            break;
            case 2:
                next = 1;
            break;
            case 3:
                next = 2;
            break;
        }
    }
    return next;
}

int current_pos(void) {
    FILE *frotpos;
    char rotpos;
    int pos;
    frotpos = popen(XRANDR_GREP_COMMAND, "r");
    fscanf(frotpos, "%c", &rotpos);
    fclose(frotpos);
    switch (rotpos) {
        case 110:
            pos = 0;
        break;
        case 108:
            pos = 1;
        break;
        case 105:
            pos = 2;
        break;
        case 114:
            pos = 3;
        break;
    }   
    return pos;
}

void rotate(int poz) {
    char buff[32];
    if ((poz == 2)||(poz == 0)) {
        system(WIDTH_COMMANDS);
    } else {
        system(HEIGHT_COMMANDS);
    }
    sprintf(buff, "xrandr -o %i", poz);
    system(buff);
}

int main(int argc, char *argv[]) {

    if(!get_lock()) {
        if (argc >= 2) {
            int cmd; 
            FILE *fparams;
            fparams = fopen(DAEMON_STATE_FILE, "w");
            if (!strncmp(argv[1], "r", 1)) { cmd = 1; }
            else if (!strncmp(argv[1], "l", 1)) { cmd = 2; }
            else if (!strncmp(argv[1], "k", 1)) { cmd = 0; }
            fprintf(fparams, "%i", cmd);
            fclose(fparams);
        }
        return 1;
    }

    int autorotate = TRUE;
    int prevmode = NIL;
    FILE *fstate;
    int tabletmode;
    FILE *fgyrovals;
    char gyroval_x[5];
    char gyroval_y[5];
    int x;
    int y;
    FILE *fargs;
    int argum = NIL;
    int next_p;
    int prev_p = current_pos();
    int last_auto_p = NIL;

    while (TRUE) {
        fstate = fopen(SWIVEL_STATE_FILE, "r");
        fscanf(fstate, "%d", &tabletmode);
        if (fargs = fopen(DAEMON_STATE_FILE, "r")) {
            if (fscanf(fargs, "%d", &argum) == NIL) { argum = NIL; }
        }
        fargs = fopen(DAEMON_STATE_FILE, "w");
        fclose(fargs);
        fclose(fstate);

        if (argum == 0) { 
            system(BUBBLE_TERMINATED);
            return 1; 
        }

        if (prevmode != tabletmode) {
            if (tabletmode) {
                system(BUBBLE_SWIVEL_DOWN);
                system(SWIVEL_DOWN_COMMANDS);
            } else {
                system(BUBBLE_SWIVEL_UP);
                system(SWIVEL_UP_COMMANDS);
                rotate(0);
            }
        }

        if (tabletmode) {
            if (argum == 1 || argum == 2) {
                next_p = next_rotation(argum);
                if (next_p == last_auto_p) {
                    rotate(next_p);
                    autorotate = TRUE;
                    last_auto_p = NIL;
                    system(BUBBLE_RETURN_POSITION);
                } else if ((autorotate)&&(current_pos() == last_auto_p)) {
                    autorotate = FALSE;
                    system(BUBBLE_START_MANUAL_ROTATION);
                } else {    
                    if (autorotate) {
                        system(BUBBLE_START_MANUAL_ROTATION);
                        last_auto_p = current_pos();
                    } else {
                        rotate(next_p);
                    }
                    autorotate = FALSE;
                }
            }
            if (autorotate) {
                fgyrovals = fopen(GYRO_STATE_FILE, "r");
                fscanf(fgyrovals, "(%4[^,], %4[^)]", &gyroval_x, &gyroval_y);
                fclose(fgyrovals);
                x = atoi(gyroval_x);
                y = atoi(gyroval_y) * (-1);
                if (y < 465) {
                    if (x < 210) {
                        next_p = 1;
                    } else if (x > 425) {
                        next_p = 3;
                    } else {
                        next_p = 2;
                    }
                } else if (y > 525) {
                    if (x < 210) {
                        next_p = 1;
                    } else if (x > 425) {
                        next_p = 3;
                    } else {
                        next_p = 0;
                    }
                } else {
                    if (x < 305) {
                        next_p = 1;     
                    } else if (x > 345) {
                        next_p = 3;
                    }
                }
                if (next_p != prev_p) {
                    rotate(next_p);
                    prev_p = next_p;
                }   
            } 
        } else {
            if (argum == 1 || argum == 2) {
                system(BUBBLE_SWIVEL_UP);
            }
        }           
        prevmode = tabletmode;
        sleep(1);
    }
    return 0;
}

最佳答案

感谢用户“inspired”的评论。现在程序运行了一个多小时,没有出现段错误。

if (fargs = fopen(DAEMON_STATE_FILE, "r")) {
    if (fscanf(fargs, "%d", &argum) == NIL) { argum = NIL; }
    fclose(fargs);
}
fargs = fopen(DAEMON_STATE_FILE, "w");
fclose(fargs);

如上所述,文件应在下次打开进行写入之前关闭。

关于C - 长时间运行的 while 循环出现段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24600211/

相关文章:

c - 如何在单个窗口中显示gtk中的文本和按钮?

c++ - C 或 C++ 中用于数字的二次方的一元运算符

c - 利用bzip2

matrix - 二元矩阵的旋转不变哈希函数

c - 不把空格算作c中的单词

C# While 循环与 For 循环?

r - 打破 R 中的嵌套循环

php - 如何在 PHP 的 while 循环中使用 <select>

java - 处理三角函数代码不起作用

java - 四元数对象旋转