Skip to content

Commit 26c03a1

Browse files
Cleanup
1 parent 16a2f80 commit 26c03a1

File tree

1 file changed

+62
-56
lines changed

1 file changed

+62
-56
lines changed

src/CommandLineUtilities/AliceLowlevelFrontend/ProgramAliceLowlevelFrontendServer.cxx

Lines changed: 62 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
/// \brief Utility that starts the ALICE Lowlevel Frontend (ALF) DIM server
33
///
44
/// This file contains a bunch of classes that together form the server part of ALF.
5-
/// It is single-threaded, because an earlier multi-threaded implementation ran into strange locking issues with DIM's
6-
/// thread, and it was determined that it would cost less time to rewrite than to debug.
75
///
86
/// The idea is that the DIM thread calls the RPC handler functions of the ProgramAliceLowlevelFrontendServer class.
97
/// These handlers then, depending on the RPC:
10-
/// a) Execute the request immediately (such as for register reads and writes)
11-
/// b) Put a corresponding command object in a lock-free thread-safe queue (such as for publish start/stop commands),
12-
/// the mCommandQueue. The main thread of ProgramAliceLowlevelFrontendServer periodically takes commands from this
13-
/// queue and handles them.
8+
/// a) Execute the request immediately (such as for register reads and writes)
9+
/// b) Put a corresponding command object in a lock-free thread-safe queue (such as for publish start/stop commands),
10+
/// the mCommandQueue. The main thread of ProgramAliceLowlevelFrontendServer periodically takes commands from this
11+
/// queue and handles them by starting or stopping a publish service.
12+
///
13+
/// Decoupling the DIM thread from the main thread was necessary to prevent strange DIM locking issues on exit.
1414
///
1515
/// \author Pascal Boeschoten ([email protected])
1616

@@ -145,7 +145,7 @@ struct Service
145145
std::unique_ptr<DimService> dimService;
146146
};
147147

148-
///
148+
/// Thread-safe queue for commands
149149
class CommandQueue
150150
{
151151
public:
@@ -235,7 +235,7 @@ class ProgramAliceLowlevelFrontendServer: public AliceO2::Common::Program
235235
for (auto link : links) {
236236
getLogger() << "Initializing link " << link << endm;
237237
LinkInfo linkInfo {serial, link};
238-
238+
239239
// Object for generating DNS names
240240
Alf::ServiceNames names(serial, link);
241241

@@ -422,6 +422,40 @@ class ProgramAliceLowlevelFrontendServer: public AliceO2::Common::Program
422422
return true;
423423
}
424424

425+
static bool isLineComment(const std::string& line)
426+
{
427+
return line.find('#') == 0;
428+
}
429+
430+
template <typename Iter>
431+
static std::vector<Sca::CommandData> linesToCommandDataVector(Iter begin, Iter end)
432+
{
433+
std::vector<Sca::CommandData> pairs;
434+
for (Iter i = begin; i != end; ++i) {
435+
const std::string& line = *i;
436+
if (!isLineComment(line)) {
437+
pairs.push_back(stringToScaCommandDataPair(line));
438+
}
439+
}
440+
return pairs;
441+
}
442+
443+
static Sca::CommandData stringToScaCommandDataPair(const std::string& string)
444+
{
445+
// The pairs are comma-separated, so we split them.
446+
std::vector<std::string> pair = split(string, scaPairSeparator().c_str());
447+
if (pair.size() != 2) {
448+
getLogger() << "SCA command-data pair not formatted correctly: parts=" << pair.size() << " str='" << string <<
449+
"'" << endm;
450+
BOOST_THROW_EXCEPTION(
451+
AlfException() << ErrorInfo::Message("SCA command-data pair not formatted correctly"));
452+
}
453+
Sca::CommandData commandData;
454+
commandData.command = convertHexString(pair[0]);
455+
commandData.data = convertHexString(pair[1]);
456+
return commandData;
457+
};
458+
425459
/// RPC handler for register reads
426460
static std::string registerRead(const std::string& parameter, BarSharedPtr channel)
427461
{
@@ -502,14 +536,11 @@ class ProgramAliceLowlevelFrontendServer: public AliceO2::Common::Program
502536
// Convert command-data pair string sequence to binary format
503537
size_t skip = 2; // Number of arguments to skip for the array
504538
ServiceDescription::ScaSequence sca;
505-
sca.commandDataPairs.resize(params.size() - skip);
506-
for (size_t i = 0; (i + skip) < params.size(); ++i) {
507-
sca.commandDataPairs[i] = stringToScaCommandDataPair(params[i + skip]);
508-
}
539+
sca.commandDataPairs = linesToCommandDataVector(params.begin() + skip, params.end());
509540

510541
auto command = std::make_unique<CommandQueue::Command>();
511542
command->start = true;
512-
command->description.type = sca;
543+
command->description.type = std::move(sca);
513544
command->description.dnsName = ServiceNames(linkInfo.serial, linkInfo.link).publishScaSequenceSubdir(dnsName);
514545
command->description.interval = std::chrono::milliseconds(int64_t(b::lexical_cast<double>(interval) * 1000.0));
515546
command->description.linkInfo = linkInfo;
@@ -593,59 +624,34 @@ class ProgramAliceLowlevelFrontendServer: public AliceO2::Common::Program
593624
{
594625
getLogger() << "SCA_SEQUENCE size=" << parameter.size() << " bytes" << endm;
595626

596-
// We first split on \n to get the pairs of SCA command and SCA data
627+
// We split on \n to get the pairs of SCA command and SCA data
597628
auto lines = split(parameter, argumentSeparator());
629+
auto commandDataPairs = linesToCommandDataVector(lines.begin(), lines.end());
630+
598631
std::stringstream resultBuffer;
599632
auto sca = Sca(*bar2, bar2->getCardType(), linkInfo.link);
600633

601-
for (const auto& line : lines) {
602-
// Walk through the tokens, these should be the pairs (or comments).
603-
if (isLineComment(line)) {
604-
continue;
605-
} else {
606-
auto commandData = stringToScaCommandDataPair(line);
607-
try {
608-
sca.write(commandData);
609-
auto result = sca.read();
610-
getLogger() << (b::format("cmd=0x%x data=0x%x result=0x%x") % commandData.command % commandData.data %
611-
result.data).str() << endm;
612-
resultBuffer << std::hex << result.data << '\n';
613-
} catch (const ScaException &e) {
614-
// If an SCA error occurs, we stop executing the sequence of commands and return the results as far as we got
615-
// them, plus the error message.
616-
getLogger() << InfoLogger::InfoLogger::Error
617-
<< (b::format("SCA_SEQUENCE cmd=0x%x data=0x%x serial=%d link=%d error='%s'") % commandData.command
618-
% commandData.data % linkInfo.serial % linkInfo.link % e.what()).str() << endm;
619-
resultBuffer << e.what();
620-
break;
621-
}
634+
for (const auto& commandData : commandDataPairs) {
635+
try {
636+
sca.write(commandData);
637+
auto result = sca.read();
638+
getLogger() << (b::format("cmd=0x%x data=0x%x result=0x%x") % commandData.command % commandData.data %
639+
result.data).str() << endm;
640+
resultBuffer << std::hex << result.data << '\n';
641+
} catch (const ScaException &e) {
642+
// If an SCA error occurs, we stop executing the sequence of commands and return the results as far as we got
643+
// them, plus the error message.
644+
getLogger() << InfoLogger::InfoLogger::Error
645+
<< (b::format("SCA_SEQUENCE cmd=0x%x data=0x%x serial=%d link=%d error='%s'") % commandData.command
646+
% commandData.data % linkInfo.serial % linkInfo.link % e.what()).str() << endm;
647+
resultBuffer << e.what();
648+
break;
622649
}
623650
}
624651

625652
return resultBuffer.str();
626653
}
627654

628-
static bool isLineComment(const std::string& line)
629-
{
630-
return line.find('#') == 0;
631-
}
632-
633-
static Sca::CommandData stringToScaCommandDataPair(const std::string& string)
634-
{
635-
// The pairs are comma-separated, so we split them.
636-
std::vector<std::string> pair = split(string, scaPairSeparator().c_str());
637-
if (pair.size() != 2) {
638-
getLogger() << "SCA command-data pair not formatted correctly: parts=" << pair.size() << " str='" << string <<
639-
"'" << endm;
640-
BOOST_THROW_EXCEPTION(
641-
AlfException() << ErrorInfo::Message("SCA command-data pair not formatted correctly"));
642-
}
643-
Sca::CommandData commandData;
644-
commandData.command = convertHexString(pair[0]);
645-
commandData.data = convertHexString(pair[1]);
646-
return commandData;
647-
};
648-
649655
/// Command queue for passing commands from DIM RPC calls (which are in separate threads) to the main program loop
650656
std::shared_ptr<CommandQueue> mCommandQueue;
651657
/// serial -> link -> vector of RPC servers

0 commit comments

Comments
 (0)