MINOR: threads: add a new function to resolve config groups and masks

In the configuration sometimes we'll omit a thread group number to designate
a global thread number range, and sometimes we'll mention the group and
designate IDs within that group. The operation is more complex than it
seems due to the need to check for ranges spanning between multiple groups
and determining groups from threads from bit masks and remapping bit masks
between local/global.

This patch adds a function to perform this operation, it takes a group and
mask on input and updates them on output. It's designed to be used by "bind"
lines but will likely be usable at other places if needed.

For situations where specified threads do not exist in the group, we have
the choice in the code between silently fixing the thread set or failing
with a message. For now the better option seems to return an error, but if
it turns out to be an issue we can easily change that in the future. Note
that it should only happen with "x/even" when group x only has one thread.
This commit is contained in:
Willy Tarreau 2021-09-29 18:59:47 +02:00
parent d57b9ff7af
commit 627def9e50
2 changed files with 103 additions and 0 deletions

View File

@ -44,6 +44,7 @@ void ha_tkill(unsigned int thr, int sig);
void ha_tkillall(int sig);
void ha_thread_relax(void);
int thread_map_to_groups();
int thread_resolve_group_mask(uint igid, ulong imask, uint *ogid, ulong *omask, char **err);
extern int thread_cpus_enabled_at_boot;

View File

@ -1087,6 +1087,108 @@ int thread_map_to_groups()
return 0;
}
/* converts a configuration thread group+mask to a global group+mask depending on
* the configured thread group id. This is essentially for use with the "thread"
* directive on "bind" lines, where "thread 2/1-3" might be turned to "4-6" for
* the global ID. It cannot be used before the thread mapping above was completed
* and the thread group number configured. Possible options:
* - igid == 0: imask represents global IDs. We have to check that all
* configured threads in the mask belong to the same group. If imask is zero
* it means everything, so for now we only support this with a single group.
* - igid > 0, imask = 0: convert local values to global values for this thread
* - igid > 0, imask > 0: convert local values to global values
*
* Returns <0 on failure, >=0 on success.
*/
int thread_resolve_group_mask(uint igid, ulong imask, uint *ogid, ulong *omask, char **err)
{
ulong mask;
uint t;
if (igid == 0) {
/* unspecified group, IDs are global */
if (!imask) {
/* all threads of all groups */
if (global.nbtgroups > 1) {
memprintf(err, "'thread' directive spans multiple groups");
return -1;
}
mask = 0;
*ogid = 1; // first and only group
*omask = all_threads_mask;
return 0;
} else {
/* some global threads */
imask &= all_threads_mask;
for (t = 0; t < global.nbthread; t++) {
if (imask & (1UL << t)) {
if (ha_thread_info[t].tg->tgid != igid) {
if (!igid)
igid = ha_thread_info[t].tg->tgid;
else {
memprintf(err, "'thread' directive spans multiple groups (at least %u and %u)", igid, ha_thread_info[t].tg->tgid);
return -1;
}
}
}
}
if (!igid) {
memprintf(err, "'thread' directive contains threads that belong to no group");
return -1;
}
/* we have a valid group, convert this to global thread IDs */
*ogid = igid;
*omask = imask << ha_tgroup_info[igid - 1].base;
return 0;
}
} else {
/* group was specified */
if (igid > global.nbtgroups) {
memprintf(err, "'thread' directive references non-existing thread group %u", igid);
return -1;
}
if (!imask) {
/* all threads of this groups. Let's make a mask from their count and base. */
*ogid = igid;
mask = 1UL << (ha_tgroup_info[igid - 1].count - 1);
mask |= mask - 1;
*omask = mask << ha_tgroup_info[igid - 1].base;
return 0;
} else {
/* some local threads. Keep only existing ones for this group */
mask = 1UL << (ha_tgroup_info[igid - 1].count - 1);
mask |= mask - 1;
if (!(mask & imask)) {
/* no intersection between the thread group's
* threads and the bind line's.
*/
#ifdef THREAD_AUTO_ADJUST_GROUPS
unsigned long new_mask = 0;
while (imask) {
new_mask |= imask & mask;
imask >>= ha_tgroup_info[igid - 1].count;
}
imask = new_mask;
#else
memprintf(err, "'thread' directive only references threads not belonging to the group");
return -1;
#endif
}
mask &= imask;
*omask = mask << ha_tgroup_info[igid - 1].base;
*ogid = igid;
return 0;
}
}
}
/* Parse the "nbthread" global directive, which takes an integer argument that
* contains the desired number of threads.
*/