/*
* Copyright (c) 2020 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* $Id: //eng/vdo-releases/aluminum/src/c++/vdo/base/threadConfig.c#2 $
*/
#include "threadConfig.h"
#include "logger.h"
#include "memoryAlloc.h"
#include "constants.h"
#include "types.h"
/**********************************************************************/
static int allocateThreadConfig(ZoneCount logicalZoneCount,
ZoneCount physicalZoneCount,
ZoneCount hashZoneCount,
ZoneCount baseThreadCount,
ThreadConfig **configPtr)
{
ThreadConfig *config;
int result = ALLOCATE(1, ThreadConfig, "thread config", &config);
if (result != VDO_SUCCESS) {
return result;
}
result = ALLOCATE(logicalZoneCount, ThreadID, "logical thread array",
&config->logicalThreads);
if (result != VDO_SUCCESS) {
freeThreadConfig(&config);
return result;
}
result = ALLOCATE(physicalZoneCount, ThreadID, "physical thread array",
&config->physicalThreads);
if (result != VDO_SUCCESS) {
freeThreadConfig(&config);
return result;
}
result = ALLOCATE(hashZoneCount, ThreadID, "hash thread array",
&config->hashZoneThreads);
if (result != VDO_SUCCESS) {
freeThreadConfig(&config);
return result;
}
config->logicalZoneCount = logicalZoneCount;
config->physicalZoneCount = physicalZoneCount;
config->hashZoneCount = hashZoneCount;
config->baseThreadCount = baseThreadCount;
*configPtr = config;
return VDO_SUCCESS;
}
/**********************************************************************/
static void assignThreadIDs(ThreadID threadIDs[],
ZoneCount count,
ThreadID *idPtr)
{
for (ZoneCount zone = 0; zone < count; zone++) {
threadIDs[zone] = (*idPtr)++;
}
}
/**********************************************************************/
int makeThreadConfig(ZoneCount logicalZoneCount,
ZoneCount physicalZoneCount,
ZoneCount hashZoneCount,
ThreadConfig **configPtr)
{
if ((logicalZoneCount == 0)
&& (physicalZoneCount == 0)
&& (hashZoneCount == 0)) {
return makeOneThreadConfig(configPtr);
}
if (physicalZoneCount > MAX_PHYSICAL_ZONES) {
return logErrorWithStringError(VDO_BAD_CONFIGURATION,
"Physical zone count %u exceeds maximum "
"(%u)",
physicalZoneCount, MAX_PHYSICAL_ZONES);
}
if (logicalZoneCount > MAX_LOGICAL_ZONES) {
return logErrorWithStringError(VDO_BAD_CONFIGURATION,
"Logical zone count %u exceeds maximum "
"(%u)",
logicalZoneCount, MAX_LOGICAL_ZONES);
}
ThreadConfig *config;
ThreadCount total = logicalZoneCount + physicalZoneCount + hashZoneCount + 2;
int result = allocateThreadConfig(logicalZoneCount, physicalZoneCount,
hashZoneCount, total, &config);
if (result != VDO_SUCCESS) {
return result;
}
ThreadID id = 0;
config->adminThread = id;
config->journalThread = id++;
config->packerThread = id++;
assignThreadIDs(config->logicalThreads, logicalZoneCount, &id);
assignThreadIDs(config->physicalThreads, physicalZoneCount, &id);
assignThreadIDs(config->hashZoneThreads, hashZoneCount, &id);
ASSERT_LOG_ONLY(id == total, "correct number of thread IDs assigned");
*configPtr = config;
return VDO_SUCCESS;
}
/**********************************************************************/
int makeZeroThreadConfig(ThreadConfig **configPtr)
{
ThreadConfig *config;
int result = ALLOCATE(1, ThreadConfig, __func__, &config);
if (result != VDO_SUCCESS) {
return result;
}
config->logicalZoneCount = 0;
config->physicalZoneCount = 0;
config->hashZoneCount = 0;
config->baseThreadCount = 0;
*configPtr = config;
return VDO_SUCCESS;
}
/**********************************************************************/
int makeOneThreadConfig(ThreadConfig **configPtr)
{
ThreadConfig *config;
int result = allocateThreadConfig(1, 1, 1, 1, &config);
if (result != VDO_SUCCESS) {
return result;
}
config->logicalThreads[0] = 0;
config->physicalThreads[0] = 0;
config->hashZoneThreads[0] = 0;
*configPtr = config;
return VDO_SUCCESS;
}
/**********************************************************************/
int copyThreadConfig(const ThreadConfig *oldConfig, ThreadConfig **configPtr)
{
ThreadConfig *config;
int result = allocateThreadConfig(oldConfig->logicalZoneCount,
oldConfig->physicalZoneCount,
oldConfig->hashZoneCount,
oldConfig->baseThreadCount,
&config);
if (result != VDO_SUCCESS) {
return result;
}
config->adminThread = oldConfig->adminThread;
config->journalThread = oldConfig->journalThread;
config->packerThread = oldConfig->packerThread;
for (ZoneCount i = 0; i < config->logicalZoneCount; i++) {
config->logicalThreads[i] = oldConfig->logicalThreads[i];
}
for (ZoneCount i = 0; i < config->physicalZoneCount; i++) {
config->physicalThreads[i] = oldConfig->physicalThreads[i];
}
for (ZoneCount i = 0; i < config->hashZoneCount; i++) {
config->hashZoneThreads[i] = oldConfig->hashZoneThreads[i];
}
*configPtr = config;
return VDO_SUCCESS;
}
/**********************************************************************/
void freeThreadConfig(ThreadConfig **configPtr)
{
if (*configPtr == NULL) {
return;
}
ThreadConfig *config = *configPtr;
*configPtr = NULL;
FREE(config->logicalThreads);
FREE(config->physicalThreads);
FREE(config->hashZoneThreads);
FREE(config);
}
/**********************************************************************/
static bool getZoneThreadName(const ThreadID threadIDs[],
ZoneCount count,
ThreadID id,
const char *prefix,
char *buffer,
size_t bufferLength)
{
if (id >= threadIDs[0]) {
ThreadID index = id - threadIDs[0];
if (index < count) {
snprintf(buffer, bufferLength, "%s%d", prefix, index);
return true;
}
}
return false;
}
/**********************************************************************/
void getVDOThreadName(const ThreadConfig *threadConfig,
ThreadID threadID,
char *buffer,
size_t bufferLength)
{
if (threadConfig->baseThreadCount == 1) {
// Historically this was the "request queue" thread.
snprintf(buffer, bufferLength, "reqQ");
return;
}
if (threadID == threadConfig->journalThread) {
snprintf(buffer, bufferLength, "journalQ");
return;
} else if (threadID == threadConfig->adminThread) {
// Theoretically this could be different from the journal thread.
snprintf(buffer, bufferLength, "adminQ");
return;
} else if (threadID == threadConfig->packerThread) {
snprintf(buffer, bufferLength, "packerQ");
return;
}
if (getZoneThreadName(threadConfig->logicalThreads,
threadConfig->logicalZoneCount,
threadID, "logQ", buffer, bufferLength)) {
return;
}
if (getZoneThreadName(threadConfig->physicalThreads,
threadConfig->physicalZoneCount,
threadID, "physQ", buffer, bufferLength)) {
return;
}
if (getZoneThreadName(threadConfig->hashZoneThreads,
threadConfig->hashZoneCount,
threadID, "hashQ", buffer, bufferLength)) {
return;
}
// Some sort of misconfiguration?
snprintf(buffer, bufferLength, "reqQ%d", threadID);
}