blob: 9fc299f0f70eed374dd1b689d7848d56bcce5ebb [file] [log] [blame]
Kamil Koczurek567fc0f2020-06-19 10:56:41 +02001// Copyright 2020 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <errno.h>
6#include <fcntl.h>
7#include <inttypes.h>
8#include <signal.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <time.h>
13#include <unistd.h>
14#include <sys/time.h>
15
16#define SIG SIGRTMIN
17
18static int out_desc = STDOUT_FILENO; /* default is stdout, prog param */
19
20static void send_msg(const char *msg) {
21 if(write(out_desc, msg, strlen(msg)) < 0) {
22 const char *err = "[ERR] send error\n";
23 /* printf isn't signal-safe
24 * as this is just error print we do not retry in case of err */
25 (void)write(STDOUT_FILENO, err, strlen(err));
26 exit(EXIT_FAILURE);
27 }
28}
29
30static void handler(int sig) {
31 struct timespec ts;
32
33 if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts)) {
34 send_msg("clock_gettimeERR: ping\n");
35 } else {
36 char msg[256];
37
38 snprintf(msg, sizeof(msg) - 1, "%" PRIu64 ".%09lu ping\n",
39 (uint64_t)ts.tv_sec, ts.tv_nsec);
40 send_msg(msg);
41 }
42}
43
44#define LLDIGITS10_MAX ((size_t)19)
45static long long safe_atoll(const char *str) {
46 char *endptr = NULL;
47 long long res = strtoll(str, &endptr, 10);
48
49 if(endptr - str != strnlen(str, LLDIGITS10_MAX)) {
50 fprintf(stderr, "[ERR] `%s` isn't an integer\n", str);
51 exit(EXIT_FAILURE);
52 }
53
54 return res;
55}
56
57int main(int argc, char* argv[]) {
58 if (argc != 4 && argc != 3) {
59 fprintf(stderr, "Usage: %s <time ms> <repetitions> [out file]\n",
60 argv[0]);
61 exit(EXIT_FAILURE);
62 }
63
64 long long msecs = safe_atoll(argv[1]);
65 long long iterations = safe_atoll(argv[2]);
66
67 if (argc == 4) {
68 out_desc = open(argv[3], O_WRONLY);
69 if(out_desc < 0) {
70 fprintf(stderr, "Couldn't open file `%s`, errno: %d\n",
71 argv[3], errno);
72 exit(EXIT_FAILURE);
73 }
74 }
75
76 // Establish handler for timer signal
77 struct sigaction sa;
78 memset(&sa, 0, sizeof(sa));
79 sa.sa_handler = handler;
80 sigemptyset(&sa.sa_mask); /* just this sig will be in mask, no SA_NODEFER */
81 if (sigaction(SIG, &sa, NULL)) {
82 fprintf(stderr, "[ERR] Couldn't set signal disposition, errno: %d\n",
83 errno);
84 exit(EXIT_FAILURE);
85 }
86
87 // Create the timer
88 struct sigevent sev;
89 timer_t timerid;
90 memset(&sev, 0, sizeof(sev));
91 sev.sigev_notify = SIGEV_SIGNAL;
92 sev.sigev_signo = SIG;
93 sev.sigev_value.sival_ptr = &timerid;
94 if (timer_create(CLOCK_REALTIME, &sev, &timerid) == -1) {
95 fprintf(stderr, "[ERR] Couldn't create the timer: %d\n", errno);
96 exit(EXIT_FAILURE);
97 }
98
99 // Start the timer
100 struct itimerspec its;
101 memset(&its, 0, sizeof(its));
102 its.it_value.tv_sec = 0;
103 its.it_value.tv_nsec = 10000000; // Timer will not start when 0
104 its.it_interval.tv_sec = msecs / 1000;
105 its.it_interval.tv_nsec = (msecs % 1000) * 1000000;
106
107 if (timer_settime(timerid, 0, &its, NULL) == -1) {
108 fprintf(stderr, "[ERR] Couldn't set timer time: %d\n", errno);
109 exit(EXIT_FAILURE);
110 }
111
112 for(int i = 0; i < iterations + 1; ++i) {
113 if(pause() < 0 && errno == EINTR && out_desc)
114 /* in case out_desc is not stdout */
115 printf("[INFO] Sent msg\n");
116 }
117
118 exit(EXIT_SUCCESS);
119}