From e66bb87909cbf4aa1c7faaae4b902f0ab1fc19cf Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Mon, 9 Feb 2026 10:03:10 +0100 Subject: [PATCH] document change in epicsThreadGetCPUs --- documentation/new-notes/PR-788.md | 8 ++++++++ modules/database/src/ioc/db/callback.h | 11 +++++++---- modules/libcom/src/pool/threadPool.c | 2 +- 3 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 documentation/new-notes/PR-788.md diff --git a/documentation/new-notes/PR-788.md b/documentation/new-notes/PR-788.md new file mode 100644 index 000000000..9dc41588c --- /dev/null +++ b/documentation/new-notes/PR-788.md @@ -0,0 +1,8 @@ +### epicsThreadGetCPUs and callbackParallelThreads + +On systems that support it (e.g. recent Linux systems), `epicsThreadGetCPUs()` +now takes the current cpu affinity mask of the calling thread into acount. +That fixes the problem that an IOC which was started with a limited affinity +mask (e.g. using `taskset`) and that called `callbackParallelThreads` with an +argument of 0 in the startup script, had started more parallel callback +threads than it has CPU cores available. diff --git a/modules/database/src/ioc/db/callback.h b/modules/database/src/ioc/db/callback.h index 07bdc0649..53595c5a9 100644 --- a/modules/database/src/ioc/db/callback.h +++ b/modules/database/src/ioc/db/callback.h @@ -193,18 +193,21 @@ DBCORE_API void callbackQueueShow(const int reset); * By default, only one thread is run for each priority (3 in total). * * Calling with count==0 will take the count from the callbackParallelThreadsDefault - * global variable (default default is 2). + * global variable (initialized to the number of CPU cores initially available to + * the main thread). * Calling with count>0 sets the number of worker threads directly. - * Calling with count<0 computes the count based on the number of CPU cores on the host. + * Calling with count<0 computes the count based on the number of CPU cores + * currently available to the calling thread, * eg. Passing -2 on an 8 core system will start 6 worker threads. * In all cases, at least one worker thread will always run. * - * A special prio name of "*" will modify all priorities. + * An empty prio name or the special value "*" will modify all priorities. * Otherwise, only the named priority is modified. + * The prio names are case insensitive. * * @param count If zero, reset to default (callbackParallelThreadsDefault global/iocsh variable). * If positive, exact number of worker threads to create. - * If negative, number of worker threads less than core count. + * If negative, reserve this many CPUs to _not_ run parallel callback threads. * @param prio Priority name. eg. "*", "LOW", "MEDIUM" or "HIGH". * @return zero on success, non-zero if called after iocInit() or with invalid arguments. * diff --git a/modules/libcom/src/pool/threadPool.c b/modules/libcom/src/pool/threadPool.c index a353aa31a..deecafb5e 100644 --- a/modules/libcom/src/pool/threadPool.c +++ b/modules/libcom/src/pool/threadPool.c @@ -338,7 +338,7 @@ LIBCOM_API epicsThreadPool* epicsThreadPoolGetShared(epicsThreadPoolConfig *opts opts = &defopts; } /* shared pools must have a minimum allowed number of workers. - * Use the number of CPU cores + * Use the number of CPU cores currently available to the calling thread. */ if (opts->maxThreads < N) opts->maxThreads = N;