chiark / gitweb /
realtime: movpos: debug output: exclude some more stuff from the default movpos output
[trains.git] / hostside / rtprio.c
1 /*
2  * realtime
3  * realtime priority
4  */
5
6 #include "realtime.h"
7
8 #include <sys/resource.h>
9 #include <signal.h>
10 #include <time.h>
11
12 #include <sched.h>
13
14 /*---------- !ALL(MEM): prevent us eating all RAM ----------*/
15
16 static void rtf_limit_MEM(void) {
17   int r;
18   struct rlimit64 rl;
19   r= getrlimit64(RLIMIT_MEMLOCK,&rl);  if (r) diee("getrlimit RLIMIT_MEMLOCK");
20   rl.rlim_cur= 4*1024*1024;
21   r= setrlimit64(RLIMIT_MEMLOCK,&rl);  if (r) diee("setrlimit RLIMIT_MEMLOCK");
22 }
23
24 /*---------- MEM: lock us into memory ----------*/
25
26 static void rtf_acquire_MEM(void) {
27   int r;
28   r= mlockall(MCL_CURRENT|MCL_FUTURE);  if (r) diee("mlockall");
29 }
30
31 /*---------- !ALL(CPU): use SIGXCPU to detect us spinning ----------*/
32
33 #define MAX_CPU_CREDIT 5 /* max burst of 5 seconds */
34 #define MAX_CPU_NTH 2 /* allow up to 50% usage, sustained */
35
36 static time_t now, last;
37 static struct rlimit rlcpu;
38 static struct sigaction sa_xcpu;
39
40 static void write_stderr(const char *m, int l) { write(2,m,l); }
41
42 static void cpulim_bomb(const char *what) __attribute__((noreturn));
43 static void cpulim_bomb(const char *what) {
44   static const char m[]= "realtime: cpu limitation failure: ";
45   int e;
46   const char *s;
47
48   e= errno;
49   write_stderr(m,sizeof(m)-1);
50   write_stderr(what,strlen(what));
51   write_stderr(": ",2);
52   
53   s= strerror(e);
54   write_stderr(s,strlen(s));
55   write_stderr("\n",1);
56   exit(-127);
57 }
58
59 static const char *cpulim_gnow(void) { /* returns what failed */
60   if (time(&now) == (time_t)-1) return "time(2)";
61   return 0;
62 }
63
64 static const char *cpulim_makepending(void) { /* returns what failed */
65   int r;
66   last= now;
67   r= sigaction(SIGXCPU, &sa_xcpu, 0);  if (r) return "sigaction SIGXCPU";
68   r= setrlimit(RLIMIT_CPU, &rlcpu);    if (r) return "setrlimit RLIMIT_CPU";
69   return 0;
70 }
71
72 static void cpulim_exceeded(void) {
73   static const char m[]= "realtime: cpu limit exceeded\n";
74   write_stderr(m,sizeof(m)-1);
75   raise(SIGXCPU);
76   abort();
77 }
78
79 static void xcpuhandler(int ignored) {
80   int credit;
81   const char *whatfailed;
82
83   whatfailed= cpulim_gnow();
84   if (whatfailed) goto fail;
85
86   credit= (now - last)/MAX_CPU_NTH;
87   if (credit <= 0) cpulim_exceeded();
88   if (credit > MAX_CPU_CREDIT) credit= MAX_CPU_CREDIT;
89   rlcpu.rlim_cur += credit;
90
91   whatfailed= cpulim_makepending();
92   if (whatfailed) goto fail;
93   return;
94
95 fail:
96   cpulim_bomb(whatfailed);
97 }
98
99 static void rtf_limit_CPU(void) {
100   int r;
101   const char *whatfailed;
102
103   memset(&sa_xcpu,0,sizeof(sa_xcpu));
104   sa_xcpu.sa_handler= xcpuhandler;
105   sigemptyset(&sa_xcpu.sa_mask);
106   sa_xcpu.sa_flags= SA_RESETHAND | SA_RESTART | SA_NODEFER;
107   
108   r= getrlimit(RLIMIT_CPU, &rlcpu);
109   if (r) { whatfailed= "getrlimit RLIMIT_CPU"; goto fail; }
110
111   whatfailed= cpulim_gnow();
112   if (whatfailed) goto fail;
113
114   rlcpu.rlim_cur= MAX_CPU_CREDIT;
115
116   whatfailed= cpulim_makepending();
117   if (whatfailed) goto fail;
118   return;
119
120 fail:
121   diee("prepare cpu limiter: %s",whatfailed);
122 }
123
124 /*---------- CPU: set hard scheduling priority ----------*/
125
126 static void rtf_acquire_CPU(void) {
127   pid_t child;
128
129   child= fork();
130   if (child<0) diee("fork for auth-sched-setscheduler");
131
132   if (!child) {
133     execlp("auth-sched-setscheduler",
134            "auth-sched-setscheduler","fifo","10",(char*)0);
135     diee("exec auth-sched-setscheduler");
136   }
137   mwaitpid(child, "auth-sched-setscheduler");
138 }
139
140 /*---------- core ----------*/
141
142 unsigned rtfeats_use= RTFEAT_DEFAULTS;
143
144 void realtime_priority(void) {
145 #define RESOURCE(NAME)                                          \
146   if (rtfeats_use & RTFEAT_##NAME) {                            \
147     if (!(rtfeats_use & RTFEAT_ALL(NAME))) rtf_limit_##NAME();  \
148     rtf_acquire_##NAME();                                       \
149   }
150   RESOURCE(MEM);
151   RESOURCE(CPU);
152 }