Добавил:
Вуз:
Предмет:
Файл:
practic4
.c/*
Выполнил:
Задание №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$
*/
Соседние файлы в предмете Системы реального времени
