Добавил:
north memphis Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

practic4

.c
Скачиваний:
0
Добавлен:
17.07.2026
Размер:
13 Кб
Скачать
/*
Выполнил: 
Задание №4 "Циклическая система управления"
Дата выполнения 02.04.2026
Версия 0.1
Общее описание программы:
	Компиляция: gcc lab4.c
	Запуск: ./a.out

*/

#define _POSIX_C_SOURCE 200809L

#include <errno.h>
#include <fcntl.h>
#include <math.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#define NSEC_PER_SEC 1000000000LL
#define CRITICAL_DEVIATION_MS 1.5
#define RUN_SECONDS 9
#define PROC_COUNT 3
#define TIMER_COUNT 4

typedef enum {
    EVENT_PROC = 1,
    EVENT_STOP = 2
} EventType;

typedef struct {
    EventType type;
    int proc_index;              // 0..2
    long long current_ns;        // CLOCK_MONOTONIC, relative to app start
    long long interval_ns;       // since previous call
    long long deviation_ns;      // interval
    int first_call;              // 1 if no previous call */
} Event;

typedef struct {
    const char *name;
    long long period_ns;
    long long last_call_ns;
    int initialized;
} ProcedureState;

static volatile sig_atomic_t g_stop_requested = 0;
static struct timespec g_start_time;
static ProcedureState g_proc[PROC_COUNT] = {
    {"Procedure #1", 500LL * 1000LL * 1000LL, 0, 0},
    {"Procedure #2", 750LL * 1000LL * 1000LL, 0, 0},
    {"Procedure #3", 1000LL * 1000LL * 1000LL, 0, 0}
};
static timer_t g_timer[TIMER_COUNT];
static int g_pipefd[2] = {-1, -1};

static long long timespec_to_ns(struct timespec ts) {
    return (long long)ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec;
}

static long long monotonic_now_since_start_ns(void) {
    struct timespec now;
    if (clock_gettime(CLOCK_MONOTONIC, &now) != 0) {
        return 0;
    }
    return timespec_to_ns(now) - timespec_to_ns(g_start_time);
}

static void write_event_to_pipe(const Event *ev) {
    ssize_t rc;
    const unsigned char *p = (const unsigned char *)ev;
    size_t remaining = sizeof(*ev);

    while (remaining > 0) {
        rc = write(g_pipefd[1], p, remaining);
        if (rc < 0) {
            if (errno == EINTR) {
                continue;
            }
            return;
        }
        p += (size_t)rc;
        remaining -= (size_t)rc;
    }
}

static void handle_timer_event(int proc_index) {
    long long now_ns = monotonic_now_since_start_ns();
    Event ev;
    memset(&ev, 0, sizeof(ev));
    ev.type = EVENT_PROC;
    ev.proc_index = proc_index;
    ev.current_ns = now_ns;

    ProcedureState *p = &g_proc[proc_index];
    if (p->initialized) {
        ev.first_call = 0;
        ev.interval_ns = now_ns - p->last_call_ns;
        ev.deviation_ns = ev.interval_ns - p->period_ns;
    } else {
        ev.first_call = 1;
        ev.interval_ns = 0;
        ev.deviation_ns = 0;
    }

    p->last_call_ns = now_ns;
    p->initialized = 1;

    write_event_to_pipe(&ev);
}

static void doControl_Procedure_1(int sig_num, siginfo_t *info, void *context) {
    (void)sig_num;
    (void)context;
    if (info == NULL) return;
    handle_timer_event(0);
}

static void doControl_Procedure_2(int sig_num, siginfo_t *info, void *context) {
    (void)sig_num;
    (void)context;
    if (info == NULL) return;
    handle_timer_event(1);
}

static void doControl_Procedure_3(int sig_num, siginfo_t *info, void *context) {
    (void)sig_num;
    (void)context;
    if (info == NULL) return;
    handle_timer_event(2);
}

static void stop_handler(int sig_num, siginfo_t *info, void *context) {
    (void)sig_num;
    (void)info;
    (void)context;
    Event ev;
    memset(&ev, 0, sizeof(ev));
    ev.type = EVENT_STOP;
    g_stop_requested = 1;
    write_event_to_pipe(&ev);
}

static void install_handler(int signo, void (*handler)(int, siginfo_t *, void *)) {
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_sigaction = handler;
    sa.sa_flags = SA_SIGINFO;
    sigemptyset(&sa.sa_mask);
    if (sigaction(signo, &sa, NULL) != 0) {
        perror("sigaction");
        exit(EXIT_FAILURE);
    }
}

static void arm_timer(timer_t *timer, int signo, int proc_index, double initial_delay_ms, double period_ms) {
    struct sigevent sev;
    memset(&sev, 0, sizeof(sev));
    sev.sigev_notify = SIGEV_SIGNAL;
    sev.sigev_signo = signo;
    sev.sigev_value.sival_int = proc_index;

    if (timer_create(CLOCK_MONOTONIC, &sev, timer) != 0) {
        perror("timer_create");
        exit(EXIT_FAILURE);
    }

    struct itimerspec its;
    memset(&its, 0, sizeof(its));
    its.it_value.tv_sec = (time_t)(initial_delay_ms / 1000.0);
    its.it_value.tv_nsec = (long)((initial_delay_ms - (double)its.it_value.tv_sec * 1000.0) * 1000000.0);
    its.it_interval.tv_sec = (time_t)(period_ms / 1000.0);
    its.it_interval.tv_nsec = (long)((period_ms - (double)its.it_interval.tv_sec * 1000.0) * 1000000.0);

    if (timer_settime(*timer, 0, &its, NULL) != 0) {
        perror("timer_settime");
        exit(EXIT_FAILURE);
    }
}

static void print_event(const Event *ev) {
    const ProcedureState *p = &g_proc[ev->proc_index];
    double current_ms = (double)ev->current_ns / 1e6;

    if (ev->first_call) {
        printf("%s [Время вызова: %.3f ms, интервал: первый вызов, отклонение: н/д]\n",
               p->name, current_ms);
    } else {
        double interval_ms = (double)ev->interval_ns / 1e6;
        double deviation_ms = (double)ev->deviation_ns / 1e6;
        printf("%s [Время вызова: %.3f ms, интервал: %.3f ms, отклонение %.3f ms]",
               p->name, current_ms, interval_ms, deviation_ms);
        if (fabs(deviation_ms) > CRITICAL_DEVIATION_MS) {
            printf("  <-- CRITICAL: отклонение больше %.1f ms", CRITICAL_DEVIATION_MS);
        }
        putchar('\n');
    }
}

static int read_full(int fd, void *buf, size_t len) {
    unsigned char *p = (unsigned char *)buf;
    size_t done = 0;
    while (done < len) {
        ssize_t rc = read(fd, p + done, len - done);
        if (rc < 0) {
            if (errno == EINTR) {
                continue;
            }
            return -1;
        }
        if (rc == 0) {
            return 0;
        }
        done += (size_t)rc;
    }
    return 1;
}

int main(void) {
    const int sig1 = SIGRTMIN;
    const int sig2 = SIGRTMIN + 1;
    const int sig3 = SIGRTMIN + 2;
    const int sig_stop = SIGRTMIN + 3;

    if (pipe(g_pipefd) != 0) {
        perror("pipe");
        return EXIT_FAILURE;
    }
    (void)fcntl(g_pipefd[0], F_SETFL, fcntl(g_pipefd[0], F_GETFL) & ~O_NONBLOCK);
    (void)fcntl(g_pipefd[1], F_SETFL, fcntl(g_pipefd[1], F_GETFL) & ~O_NONBLOCK);

    install_handler(sig1, doControl_Procedure_1);
    install_handler(sig2, doControl_Procedure_2);
    install_handler(sig3, doControl_Procedure_3);
    install_handler(sig_stop, stop_handler);

    if (clock_gettime(CLOCK_MONOTONIC, &g_start_time) != 0) {
        perror("clock_gettime");
        return EXIT_FAILURE;
    }

    arm_timer(&g_timer[0], sig1, 0, 500.0, 500.0);
    arm_timer(&g_timer[1], sig2, 1, 750.0, 750.0);
    arm_timer(&g_timer[2], sig3, 2, 1000.0, 1000.0);
    arm_timer(&g_timer[3], sig_stop, 3, RUN_SECONDS * 1000.0, 0.0);

    printf("Starting cyclic control for %d seconds...\n", RUN_SECONDS);
    fflush(stdout);

    while (1) {
        Event ev;
        int rc = read_full(g_pipefd[0], &ev, sizeof(ev));
        if (rc < 0) {
            perror("read");
            break;
        }
        if (rc == 0) {
            break;
        }

        if (ev.type == EVENT_PROC) {
            print_event(&ev);
        } else if (ev.type == EVENT_STOP) {
            puts("Finished.");
            break;
        }

        if (g_stop_requested) {
            struct pollfd pfd = {.fd = g_pipefd[0], .events = POLLIN, .revents = 0};
            int prc = poll(&pfd, 1, 0);
            if (prc <= 0 || !(pfd.revents & POLLIN)) {
                break;
            }
        }
    }

    for (int i = 0; i < TIMER_COUNT; ++i) {
        timer_delete(g_timer[i]);
    }
    close(g_pipefd[0]);
    close(g_pipefd[1]);

    return EXIT_SUCCESS;
}

/* ЛОГ
@debian:~/Desktop$ gcc lab4.c
@debian:~/Desktop$ ./a.out
Starting cyclic control for 9 seconds...
Procedure #1 [Время вызова: 501.395 ms, интервал: первый вызов, отклонение: н/д]
Procedure #2 [Время вызова: 752.660 ms, интервал: первый вызов, отклонение: н/д]
Procedure #3 [Время вызова: 1001.893 ms, интервал: первый вызов, отклонение: н/д]
Procedure #1 [Время вызова: 1001.901 ms, интервал: 500.507 ms, отклонение 0.507 ms]
Procedure #2 [Время вызова: 1500.422 ms, интервал: 747.762 ms, отклонение -2.238 ms]  <-- CRITICAL: отклонение больше 1.5 ms
Procedure #1 [Время вызова: 1500.428 ms, интервал: 498.526 ms, отклонение -1.474 ms]
Procedure #3 [Время вызова: 2001.554 ms, интервал: 999.661 ms, отклонение -0.339 ms]
Procedure #1 [Время вызова: 2001.559 ms, интервал: 501.131 ms, отклонение 1.131 ms]
Procedure #2 [Время вызова: 2250.702 ms, интервал: 750.280 ms, отклонение 0.280 ms]
Procedure #1 [Время вызова: 2500.525 ms, интервал: 498.966 ms, отклонение -1.034 ms]
Procedure #3 [Время вызова: 3002.233 ms, интервал: 1000.679 ms, отклонение 0.679 ms]
Procedure #2 [Время вызова: 3002.239 ms, интервал: 751.537 ms, отклонение 3.537 ms]  <-- CRITICAL: отклонение больше 1.5 ms
Procedure #1 [Время вызова: 3002.241 ms, интервал: 501.716 ms, отклонение 1.716 ms]  <-- CRITICAL: отклонение больше 1.5 ms
Procedure #1 [Время вызова: 3500.425 ms, интервал: 498.184 ms, отклонение -1.816 ms]  <-- CRITICAL: отклонение больше 1.5 ms
Procedure #2 [Время вызова: 3754.289 ms, интервал: 752.050 ms, отклонение 2.050 ms]  <-- CRITICAL: отклонение больше 1.5 ms
Procedure #3 [Время вызова: 4000.718 ms, интервал: 998.485 ms, отклонение -1.515 ms]  <-- CRITICAL: отклонение больше 1.5 ms
Procedure #1 [Время вызова: 4000.724 ms, интервал: 500.299 ms, отклонение 0.299 ms]
Procedure #2 [Время вызова: 4501.615 ms, интервал: 747.326 ms, отклонение -2.674 ms]  <-- CRITICAL: отклонение больше 1.5 ms
Procedure #1 [Время вызова: 4501.622 ms, интервал: 500.898 ms, отклонение 0.898 ms]
Procedure #3 [Время вызова: 5001.697 ms, интервал: 1000.979 ms, отклонение 0.979 ms]
Procedure #1 [Время вызова: 5001.704 ms, интервал: 500.082 ms, отклонение 0.082 ms]
Procedure #2 [Время вызова: 5251.332 ms, интервал: 749.717 ms, отклонение -0.283 ms]
Procedure #1 [Время вызова: 5501.070 ms, интервал: 499.366 ms, отклонение -0.634 ms]
Procedure #3 [Время вызова: 6002.709 ms, интервал: 1001.012 ms, отклонение 1.012 ms]
Procedure #2 [Время вызова: 6002.715 ms, интервал: 751.383 ms, отклонение 1.383 ms]
Procedure #1 [Время вызова: 6002.716 ms, интервал: 501.646 ms, отклонение 1.646 ms]  <-- CRITICAL: отклонение больше 1.5 ms
Procedure #1 [Время вызова: 6504.743 ms, интервал: 502.027 ms, отклонение 2.027 ms]  <-- CRITICAL: отклонение больше 1.5 ms
Procedure #2 [Время вызова: 6750.711 ms, интервал: 747.996 ms, отклонение -2.004 ms]  <-- CRITICAL: отклонение больше 1.5 ms
Procedure #3 [Время вызова: 7001.108 ms, интервал: 998.398 ms, отклонение -1.602 ms]  <-- CRITICAL: отклонение больше 1.5 ms
Procedure #1 [Время вызова: 7001.114 ms, интервал: 496.371 ms, отклонение -3.629 ms]  <-- CRITICAL: отклонение больше 1.5 ms
Procedure #2 [Время вызова: 7500.105 ms, интервал: 749.394 ms, отклонение -0.606 ms]
Procedure #1 [Время вызова: 7500.111 ms, интервал: 498.997 ms, отклонение -1.003 ms]
Procedure #3 [Время вызова: 8001.701 ms, интервал: 1000.593 ms, отклонение 0.593 ms]
Procedure #1 [Время вызова: 8001.707 ms, интервал: 501.596 ms, отклонение 1.596 ms]  <-- CRITICAL: отклонение больше 1.5 ms
Procedure #2 [Время вызова: 8250.684 ms, интервал: 750.579 ms, отклонение 0.579 ms]
Procedure #1 [Время вызова: 8501.401 ms, интервал: 499.694 ms, отклонение -0.306 ms]
Finished.
@debian:~/Desktop$
*/
Соседние файлы в предмете Системы реального времени