|
|
Home » Community » Newbie corner » Stopping ReadStdIn() function
Stopping ReadStdIn() function [message #57030] |
Sun, 16 May 2021 20:08 |
|
Xemuth
Messages: 387 Registered: August 2018 Location: France
|
Senior Member |
|
|
Hello,
I'm working on a project which implement a tiny command line interface :
Upp::String command;
LOG("Command line interface ready");
while(command != "exit" && !secureStop){
command = ToLower(ReadStdIn());
Cout() << ProcessCommandLine(command);
}
secureStop boolean is use to stop my app (in case of SIGINT) however, since my while is in blocking mode because of ReadStdIn() It wont stop my app until I write something to console.
Is there a way to set a timeout or stop the ReadStdIn() ?
[Updated on: Sun, 16 May 2021 20:08] Report message to a moderator
|
|
|
|
Re: Stopping ReadStdIn() function [message #57035 is a reply to message #57031] |
Mon, 17 May 2021 09:28 |
|
Xemuth
Messages: 387 Registered: August 2018 Location: France
|
Senior Member |
|
|
Hello Oblivion, Thanks for your help.
In my actual code I'm doing this :
CV2DServer* serverPtr;
CONSOLE_APP_MAIN
{
StdLogSetup(LOG_COUT | LOG_FILE | LOG_TIMESTAMP);
CV2DServer server(LISTENING_PORT, TICK_RATE);
serverPtr = &server;
std::signal(SIGINT,static_cast<__p_sig_fn_t>([](int s)->void{serverPtr->StopServer();}));
server.StartServer();
}
It is a bit different from your approch but I guess it is partially equal.
The probleme is, in my StartServer which is equal to this :
void CV2DServer::StartServer(){
serverThread.Start(THISBACK(ServerRoutine));
Upp::String command;
LOG("Command line interface ready");
while(command != "exit" && !secureStop){
command = ToLower(ReadStdIn());
Cout() << ProcessCommandLine(command);
}
server.Close();
client.Close();
serverThread.ShutdownThreads();
serverThread.Wait();
}
The ReadStdIn() block my code until I write something in console. It mean, even if I raise a SIGINT event, my code will catch it, turn the boolean secureStop to true but wont stop until I write something in console. This is problematique, that's why I'm looking for a way to stop the ReadStdIn().
I will try the way you do it after work and will update this post. But I'm pretty sure result will be the same
[Updated on: Mon, 17 May 2021 09:30] Report message to a moderator
|
|
|
Re: Stopping ReadStdIn() function [message #57042 is a reply to message #57035] |
Mon, 17 May 2021 10:46 |
Oblivion
Messages: 1143 Registered: August 2007
|
Senior Contributor |
|
|
Hello Xemuth,
You are insalling a SIGINT hook and from that point on, it is your responsibility to send a SIGINT to the foreground process:
std::signal(SIGINT,static_cast<__p_sig_fn_t>([](int s)->void{serverPtr->StopServer();}));
One way might be to set the SIGINT hook to default after you've clean up the application:
static void SecureStop(int)
{
// Cleanup the app here...
signal(SIGINT, SIG_DFL); // unsintall your hook.
raise(SIGINT); // Let OS handle it.
}
This way, you shouldn't even need "done" flag...
Example:
static std::atomic<bool> done(false);
static void SecureStop(int)
{
// Do app cleanup here..
done = true;
signal(SIGINT, SIG_DFL); // unsintall the hook.
raise(SIGINT);
}
CONSOLE_APP_MAIN
{
StdLogSetup(LOG_COUT|LOG_FILE);
auto worker = Async([] { // Simulate the signal request...
int timeout = 5000;
int t = msecs();
while(msecs(t) < timeout) {
if(CoWork::IsCanceled())
return;
Sleep(10);
}
if(!done) {
RLOG("rasigin SIGINT with custom hook...");
raise(SIGINT);
}
});
signal(SIGINT, &SecureStop);
String s;
while(s != "exit") {
s = ReadStdIn();
}
worker.Cancel();
}
Please note that this may work, because the code you posted is very simple. This isn't a good way to handle it if it get complex, as you need to make your cleanup-code thread-safe.
Best regards,
Oblivion
Github page: https://github.com/ismail-yilmaz
upp-components: https://github.com/ismail-yilmaz/upp-components
Bobcat the terminal emulator: https://github.com/ismail-yilmaz/Bobcat
[Updated on: Mon, 17 May 2021 11:06] Report message to a moderator
|
|
|
Re: Stopping ReadStdIn() function [message #57043 is a reply to message #57030] |
Mon, 17 May 2021 11:50 |
Oblivion
Messages: 1143 Registered: August 2007
|
Senior Contributor |
|
|
You can also write a non-blocking version of ReadStdIn so that you can set a timeout value. (this is for posix, but it can be easily adapted to windows)
void SetNonBlocking()
{
fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);
}
void SetBlocking()
{
fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) & ~O_NONBLOCK);
}
String ReadStdIn2(int timeout)
{
String r;
SetNonBlocking();
int t = msecs();
do {
SocketWaitEvent we;
we.Add(STDIN_FILENO, WAIT_READ);
if(we.Wait(10) && (we[0] & WAIT_READ)) {
int c = 0;
int n = read(STDIN_FILENO, (char*) &c, 1);
if(c == '\n')
break;
if(n > 0) {
r.Cat(c);
t = msecs();
}
}
}
while(msecs(t) < timeout && !done);
SetBlocking();
return r.GetCount() ? r : String::GetVoid();
}
Best regards,
Oblivion
Github page: https://github.com/ismail-yilmaz
upp-components: https://github.com/ismail-yilmaz/upp-components
Bobcat the terminal emulator: https://github.com/ismail-yilmaz/Bobcat
[Updated on: Mon, 17 May 2021 13:01] Report message to a moderator
|
|
|
Re: Stopping ReadStdIn() function [message #57045 is a reply to message #57043] |
Mon, 17 May 2021 18:24 |
|
Xemuth
Messages: 387 Registered: August 2018 Location: France
|
Senior Member |
|
|
Hello again Oblivion, I like the tiemout approach. here is what I did :
String ReadCmd(int timeout)
{
String r;
int time = msecs();
while(msecs(time) < timeout){
int c = 0;
int n = read(STDIN_FILENO, (char*) &c, 1);
if(c == '\n')
break;
if(n > 0) {
r.Cat(c);
time = msecs();
}
}
return r.GetCount() ? r : String::GetVoid();
}
It now work perfectly. Thanks for your precious help !
[Updated on: Mon, 17 May 2021 18:29] Report message to a moderator
|
|
|
Goto Forum:
Current Time: Sat Dec 14 15:02:34 CET 2024
Total time taken to generate the page: 0.02708 seconds
|
|
|