From: ian Date: Sat, 17 May 2008 15:46:32 +0000 (+0000) Subject: set scheduler priority X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ijackson/git?a=commitdiff_plain;h=4986ef49edb19d78a1d45b8d2d19bf2c50efe9a2;p=trains.git set scheduler priority --- diff --git a/hostside/Makefile b/hostside/Makefile index 76cd42a..a9c8eeb 100644 --- a/hostside/Makefile +++ b/hostside/Makefile @@ -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) \ diff --git a/hostside/realtime.c b/hostside/realtime.c index f76e922..eda9fc9 100644 --- a/hostside/realtime.c +++ b/hostside/realtime.c @@ -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); diff --git a/hostside/realtime.h b/hostside/realtime.h index fb98a72..35a66ce 100644 --- a/hostside/realtime.h +++ b/hostside/realtime.h @@ -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); diff --git a/hostside/rtprio.c b/hostside/rtprio.c index f8f5e3b..8e25688 100644 --- a/hostside/rtprio.c +++ b/hostside/rtprio.c @@ -1,56 +1,138 @@ -#include +/* + * realtime + * realtime priority + */ + +#include "realtime.h" + #include #include #include -#include -#include -#include - -#define MAXCREDIT 5 -#define MAXNTH 2 + +#include + +/*---------- !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); }