chiark / gitweb /
set scheduler priority
authorian <ian>
Sat, 17 May 2008 15:46:32 +0000 (15:46 +0000)
committerian <ian>
Sat, 17 May 2008 15:46:32 +0000 (15:46 +0000)
hostside/Makefile
hostside/realtime.c
hostside/realtime.h
hostside/rtprio.c

index 76cd42ad267297cb7d398525d9fc30645bd8b1ae..a9c8eeb344ee18fbb81e77bc72c79d79f3059dbc 100644 (file)
@@ -34,7 +34,7 @@ REALTIME_CORE=        realtime.o startup.o safety.o trackloc.o                \
                 cmdinput.o commands.o obc.o eventhelp.o simulate.o     \
                 record.o record-l.o record-y.o                         \
                 utils.o serialio.o parseutils.o auproto-pic.o          \
-                nmra.o encode.o movpos.o                               \
+                nmra.o encode.o movpos.o  rtprio.o                     \
                 ../layout/ours.layout-data.o
 
 realtime:      $(REALTIME_CORE)                                \
index f76e922dd24b1c41af2d4164b7a5379400aecc99..eda9fc951525d824394bf0ffef9730a13314a233 100644 (file)
@@ -323,7 +323,7 @@ void serial_transmit(const PicInsn *pi) {
 int main(int argc, const char **argv) {
   oop_source_sys *sys_events;
   const char *arg;
-  int r;
+  int r, c;
 
   persist_map_veryearly();
 
@@ -342,6 +342,19 @@ int main(int argc, const char **argv) {
       case 'V': simlog_full=1;                           break;
       case 'L': logcopy_fn= arg;                  arg=0; break;
       case 'S': simulate= arg;                    arg=0; break;
+      case 'R':
+       rtfeats_use= 0;
+       while ((c= *arg++)) {
+         switch (c) {
+         case 'd': rtfeats_use |= RTFEAT_DEFAULTS;     break;
+         case 'p': rtfeats_use |= RTFEAT_CPU;          break;
+         case 'P': rtfeats_use |= RTFEAT_ALL(CPU);     break;
+         case 'm': rtfeats_use |= RTFEAT_MEM;          break;
+         case 'M': rtfeats_use |= RTFEAT_ALL(MEM);     break;
+         default: badusage("unknown -R suboption");
+         }
+       }
+       break;
       default: badusage("unknown option");
       }
     }
@@ -365,6 +378,8 @@ int main(int argc, const char **argv) {
     events->on_fd(events, serial_fd, OOP_READ, serial_readable, 0);
     events->on_fd(events, serial_fd, OOP_EXCEPTION, read_exception, 0);
 
+    if (rtfeats_use & RTFEAT_DEFAULTS)
+      rtfeats_use |= RTFEAT_CPU | RTFEAT_MEM;
   } else {
     sim_initialise(logcopy_fn);
     sys_events= 0;
@@ -372,6 +387,7 @@ int main(int argc, const char **argv) {
 
   persist_entrails_interpret();
   records_parse(argv);
+  realtime_priority();
   sta_startup();
 
   if (!simulate) oop_sys_run(sys_events);
index fb98a7237dc340454af4f4eab4cfe136f5e0251c..35a66ce6f4f5fd741af0c3c1cd3df79d110091be 100644 (file)
@@ -215,6 +215,21 @@ void toev_start(TimeoutEvent*);   /* IR -> R; reads duration */
   /* if duration is -1 then is same as toev_stop */
 void toev_stop(TimeoutEvent*);    /* IR -> I */
 
+/*---------- from rtprio.c ----------*/
+
+void realtime_priority(void);
+
+#define RTFEAT_DEFAULTS  0100u /* turns on MLOCK and SCHEDPRIO iff not sim */
+#define RTFEAT_MEM       0001u /* mlock */
+#define RTFEAT_CPU       0002u /* hard CPU scheduling priority */
+
+#define RTFEAT_ALL_SHIFT 16
+#define RTFEAT_ALL(x) (RTFEAT_##x << RTFEAT_ALL_SHIFT)
+  /* RTFEAT_ALL(FOO) is relevant only if RTFEAT_FOO selected, and means
+   *  not to apply the normal limit to the grabbing of FOO */
+
+extern unsigned rtfeats_use;
+
 /*---------- tbi ----------*/
 
 void choreographers_all_abandon(void);
index f8f5e3b40637b5a4858a37c0e1b0ffff2c11de3b..8e25688a20b2d8172e70faaf9576d9888881f057 100644 (file)
-#include <sys/time.h>
+/*
+ * realtime
+ * realtime priority
+ */
+
+#include "realtime.h"
+
 #include <sys/resource.h>
 #include <signal.h>
 #include <time.h>
-#include <unistd.h>
-#include <assert.h>
-#include <string.h>
-#define MAXCREDIT 5
-#define MAXNTH 2
+
+#include <sched.h>
+
+/*---------- !ALL(MEM): prevent us eating all RAM ----------*/
+
+static void rtf_limit_MEM(void) { }
+
+/*---------- MEM: lock us into memory ----------*/
+
+static void rtf_acquire_MEM(void) { }
+
+/*---------- !ALL(CPU): use SIGXCPU to detect us spinning ----------*/
+
+#define MAX_CPU_CREDIT 5 /* max burst of 5 seconds */
+#define MAX_CPU_NTH 2 /* allow up to 50% usage, sustained */
 
 static time_t now, last;
 static struct rlimit rlcpu;
-static struct sigaction saxcpu;
+static struct sigaction sa_xcpu;
+
+static void write_stderr(const char *m, int l) { write(2,m,l); }
 
-static void gnow(void) { time(&now); }
+static void cpulim_bomb(const char *what) __attribute__((noreturn));
+static void cpulim_bomb(const char *what) {
+  static const char m[]= "realtime: cpu limitation failure: ";
+  int e;
+  const char *s;
+
+  e= errno;
+  write_stderr(m,sizeof(m)-1);
+  write_stderr(what,strlen(what));
+  write_stderr(": ",2);
+  
+  s= strerror(e);
+  write_stderr(s,strlen(s));
+  write_stderr("\n",1);
+  exit(-127);
+}
+
+static const char *cpulim_gnow(void) { /* returns what failed */
+  if (time(&now) == (time_t)-1) return "time(2)";
+  return 0;
+}
 
-static void makepending(void) {
+static const char *cpulim_makepending(void) { /* returns what failed */
   int r;
   last= now;
-  r= sigaction(SIGXCPU, &saxcpu, 0); assert(!r);
-  r= setrlimit(RLIMIT_CPU, &rlcpu); assert(!r);
+  r= sigaction(SIGXCPU, &sa_xcpu, 0);  if (r) return "sigaction SIGXCPU";
+  r= setrlimit(RLIMIT_CPU, &rlcpu);    if (r) return "setrlimit RLIMIT_CPU";
+  return 0;
 }
 
-static void exceeded(void) {
-  const char m[]= "cpu limit exceeded\n";
-  write(2,m,sizeof(m)-1);
+static void cpulim_exceeded(void) {
+  static const char m[]= "realtime: cpu limit exceeded\n";
+  write_stderr(m,sizeof(m)-1);
   raise(SIGXCPU);
+  abort();
 }
 
 static void xcpuhandler(int ignored) {
   int credit;
-  gnow();
-  credit= (now - last)/MAXNTH;
-  if (credit <= 0) exceeded();
-  if (credit > MAXCREDIT) credit= MAXCREDIT;
+  const char *whatfailed;
+
+  whatfailed= cpulim_gnow();
+  if (whatfailed) goto fail;
+
+  credit= (now - last)/MAX_CPU_NTH;
+  if (credit <= 0) cpulim_exceeded();
+  if (credit > MAX_CPU_CREDIT) credit= MAX_CPU_CREDIT;
   rlcpu.rlim_cur += credit;
-  makepending();
+
+  whatfailed= cpulim_makepending();
+  if (whatfailed) goto fail;
+  return;
+
+fail:
+  cpulim_bomb(whatfailed);
 }
 
-int main(void) {
+static void rtf_limit_CPU(void) {
   int r;
+  const char *whatfailed;
 
-  memset(&saxcpu,0,sizeof(saxcpu));
-  saxcpu.sa_handler= xcpuhandler;
-  sigemptyset(&saxcpu.sa_mask);
-  saxcpu.sa_flags= SA_RESETHAND | SA_RESTART | SA_NODEFER;
+  memset(&sa_xcpu,0,sizeof(sa_xcpu));
+  sa_xcpu.sa_handler= xcpuhandler;
+  sigemptyset(&sa_xcpu.sa_mask);
+  sa_xcpu.sa_flags= SA_RESETHAND | SA_RESTART | SA_NODEFER;
   
-  r= getrlimit(RLIMIT_CPU, &rlcpu); assert(!r);
+  r= getrlimit(RLIMIT_CPU, &rlcpu);
+  if (r) { whatfailed= "getrlimit RLIMIT_CPU"; goto fail; }
+
+  whatfailed= cpulim_gnow();
+  if (whatfailed) goto fail;
+
+  rlcpu.rlim_cur= MAX_CPU_CREDIT;
+
+  whatfailed= cpulim_makepending();
+  if (whatfailed) goto fail;
+  return;
+
+fail:
+  diee("prepare cpu limiter: %s",whatfailed);
+}
+
+/*---------- CPU: set hard scheduling priority ----------*/
+
+static void rtf_acquire_CPU(void) {
+  struct sched_param sp;
+  int r;
+  
+  sp.sched_priority= 10;
+  r= sched_setscheduler(0, SCHED_FIFO, &sp);
+  if (r) diee("sched_setscheduler");
+}
+
+/*---------- core ----------*/
 
-  gnow();
-  rlcpu.rlim_cur= MAXCREDIT;
-  makepending();
+unsigned rtfeats_use= RTFEAT_DEFAULTS;
 
-  for (;;);
+void realtime_priority(void) {
+#define RESOURCE(NAME)                                         \
+  if (rtfeats_use & RTFEAT_##NAME) {                           \
+    if (!(rtfeats_use & RTFEAT_ALL(NAME))) rtf_limit_##NAME(); \
+    rtf_acquire_##NAME();                                      \
+  }
+  RESOURCE(MEM);
+  RESOURCE(CPU);
 }