22 #include <sys/types.h>
29 #include <epicsStdio.h>
30 #include <epicsMath.h>
31 #include <epicsThread.h>
32 #include <epicsMutex.h>
38 #define epicsExportSharedSymbols
43 extern int epicsThreadGetPosixPriority(epicsThreadOSD *pthreadInfo);
67 static ELLLIST threadRules = ELLLIST_INIT;
68 static epicsMutexId listLock;
69 static unsigned int cpuspecLen;
70 static char *sysConfigFile =
"/etc/rtrules";
71 static ENV_PARAM userHome = {
"HOME",
"/"};
72 static ENV_PARAM userConfigFile = {
"EPICS_MCORE_USERCONFIG",
".rtrules"};
82 static void parseModifiers(
threadRule *prule,
const char *policy,
const char *priority,
const char *cpus)
84 if (policy &&
'*' != policy[0] &&
'\0' != policy[0]) {
87 if (-1 == prule->policy) {
88 prule->ch_policy = prule->policy = 0;
91 if (priority &&
'*' != priority[0] &&
'\0' != priority[0]) {
92 prule->ch_priority = 1;
93 if (
'+' == priority[0] ||
'-' == priority[0]) {
94 prule->rel_priority = 1;
96 prule->priority = atoi(priority);
97 if (prule->priority > epicsThreadPriorityMax) prule->priority = epicsThreadPriorityMax;
98 if (prule->priority < epicsThreadPriorityMin) prule->priority = epicsThreadPriorityMin;
100 if (cpus &&
'*' != cpus[0] &&
'\0' != cpus[0]) {
101 prule->ch_affinity = 1;
109 long mcoreThreadRuleAdd(
const char *name,
const char *policy,
const char *priority,
const char *cpus,
const char *pattern)
115 errlogPrintf(
"Memory allocation error\n");
119 prule->name = strdup(name);
120 prule->pattern = strdup(pattern);
121 prule->cpus = strdup(cpus);
122 if (!prule->name || !prule->pattern || !prule->cpus) {
123 errlogPrintf(
"Memory allocation error\n");
124 free(prule->name); free(prule->pattern); free(prule->cpus);
129 parseModifiers(prule, policy, priority, cpus);
130 regcomp(&prule->reg, prule->pattern, (REG_EXTENDED || REG_NOSUB));
132 epicsMutexLock(listLock);
134 ellAdd(&threadRules, &prule->node);
135 epicsMutexUnlock(listLock);
146 epicsMutexLock(listLock);
147 prule = (
threadRule *) ellFirst(&threadRules);
149 if (0 == strcmp(name, prule->name)) {
150 ellDelete(&threadRules, &prule->node);
151 epicsMutexUnlock(listLock);
153 free(prule->pattern);
155 regfree(&prule->reg);
161 epicsMutexUnlock(listLock);
170 const int buflen = 128;
173 epicsMutexLock(listLock);
174 prule = (
threadRule *) ellFirst(&threadRules);
176 fprintf(epicsGetStdout(),
"No rules defined.\n");
177 epicsMutexUnlock(listLock);
180 fprintf(epicsGetStdout(),
" NAME PRIO POLICY %-*s PATTERN\n", cpuspecLen,
"AFFINITY");
183 fprintf(epicsGetStdout(),
"%16s ",
185 if (prule->ch_priority) {
186 if (prule->rel_priority) {
187 fprintf(epicsGetStdout(),
"%+4d ", prule->priority);
189 fprintf(epicsGetStdout(),
"%4d ", prule->priority);
192 fprintf(epicsGetStdout(),
" * ");
194 fprintf(epicsGetStdout(),
"%6s %-*s %s\n",
196 cpuspecLen, prule->ch_affinity?buf:
"*",
201 epicsMutexUnlock(listLock);
210 static void modifyRTProperties(epicsThreadId
id,
threadRule *prule)
214 if (prule->ch_policy || prule->ch_priority) {
215 status = pthread_attr_getschedparam(&id->attr, &id->schedParam);
218 status = pthread_attr_getschedpolicy(&id->attr, &id->schedPolicy);
222 if (prule->ch_policy) {
223 id->schedPolicy = prule->policy;
224 status = pthread_attr_setschedpolicy(&id->attr, id->schedPolicy);
227 if (SCHED_FIFO == prule->policy || SCHED_RR == prule->policy) {
228 id->isRealTimeScheduled = 1;
230 id->isRealTimeScheduled = 0;
234 if (prule->ch_priority) {
235 unsigned int priority;
236 if (prule->rel_priority) {
237 priority =
id->osiPriority + prule->priority;
238 if (priority > epicsThreadPriorityMax) priority = epicsThreadPriorityMax;
239 if (priority < epicsThreadPriorityMin) priority = epicsThreadPriorityMin;
241 priority = prule->priority;
243 id->osiPriority = priority;
244 id->schedParam.sched_priority = epicsThreadGetPosixPriority(
id);
245 status = pthread_attr_setschedparam(&id->attr, &id->schedParam);
250 status = pthread_setschedparam(id->tid, id->schedPolicy, &id->schedParam);
255 if (prule->ch_affinity) {
256 status = pthread_attr_setaffinity_np(&id->attr,
261 status = pthread_setaffinity_np(id->tid,
269 static void threadStartHook (epicsThreadId
id)
273 epicsMutexLock(listLock);
274 prule = (
threadRule *) ellFirst(&threadRules);
276 epicsMutexUnlock(listLock);
280 if (0 == regexec(&prule->reg, id->name, 0, NULL, 0)) {
281 modifyRTProperties(
id, prule);
285 epicsMutexUnlock(listLock);
291 void mcoreThreadModify(epicsThreadId
id,
const char *policy,
const char *priority,
const char *cpus)
296 parseModifiers(&rule, policy, priority, cpus);
297 modifyRTProperties(
id, &rule);
306 static int readRulesFromFile(
const char *file)
308 const int linelen = 256;
309 const char sep =
':';
313 FILE *fp = fopen(file,
"r");
316 errlogPrintf(
"mcoreThreadRules: can't open rules file %s\n", file);
318 unsigned int lineno = 0;
320 while (fgets(line, linelen, fp)) {
326 cp += strspn(cp,
" \t\r\n");
327 if (*cp ==
'#' || *cp ==
'\0')
329 for (i = 1; i < 5; i++) {
330 sp = strchr(cp, sep);
332 errlogPrintf(
"mcoreThreadRules: error parsing line %d of file %s\n", lineno, file);
338 if ((sp = strpbrk(cp,
"\n\r"))) {
349 static void once(
void *arg)
359 listLock = epicsMutexMustCreate();
361 envGetConfigParam(&userHome,
sizeof(userFile), userFile);
362 envGetConfigParam(&userConfigFile,
sizeof(userRel), userRel);
363 if (userFile[strlen(userFile)-1] !=
'/')
364 strcat(userFile,
"/");
365 strncat(userFile, userRel, len-strlen(userFile)-1);
367 count = readRulesFromFile(sysConfigFile);
368 printf(
"MCoreUtils: Read %d thread rule(s) from %s\n", count, sysConfigFile);
370 count = readRulesFromFile(userFile);
371 printf(
"MCoreUtils: Read %d thread rule(s) from %s\n", count, userFile);
373 epicsThreadHookAdd(threadStartHook);
381 static epicsThreadOnceId onceFlag = EPICS_THREAD_ONCE_INIT;
382 epicsThreadOnce(&onceFlag, once, NULL);
long mcoreThreadRuleAdd(const char *name, const char *policy, const char *priority, const char *cpus, const char *pattern)
Add or replace a thread rule.
void mcoreThreadModify(epicsThreadId id, const char *policy, const char *priority, const char *cpus)
Modify a thread's real-time properties.
void mcoreThreadRuleDelete(const char *name)
Delete a thread rule.
void mcoreThreadRulesShow(void)
Print a comprehensive list of the thread rules.
void mcoreThreadRulesInit(void)
Initialization routine.
struct threadRule threadRule
A thread rule.
const char * policyToStr(const int policy)
Convert scheduling policy to string.
void cpusetToStr(char *set, size_t len, const cpu_set_t *cpuset)
Convert a cpuset into its string specification (e.g. "0,2-3").
void strToCpuset(cpu_set_t *cpuset, const char *spec)
Convert a cpuset string specification (e.g. "0,2-3") to a cpuset.
int strToPolicy(const char *string)
Convert string policy specification to policy.
#define checkStatus(status, message)