Safer console shutdown.

develop
Petr Mrázek 2011-07-17 11:06:45 +02:00
parent 9f822af45a
commit fdb5397a1d
5 changed files with 168 additions and 91 deletions

@ -262,7 +262,7 @@ namespace DFHack
/// beep. maybe? /// beep. maybe?
//void beep (void); //void beep (void);
/// A simple line edit (raw mode) /// A simple line edit (raw mode)
int lineedit(const std::string& prompt, std::string& output) int lineedit(const std::string& prompt, std::string& output, SDL::Mutex * lock)
{ {
output.clear(); output.clear();
this->prompt = prompt; this->prompt = prompt;
@ -271,9 +271,9 @@ namespace DFHack
print(prompt.c_str()); print(prompt.c_str());
fflush(dfout_C); fflush(dfout_C);
// FIXME: what do we do here??? // FIXME: what do we do here???
//SDL_mutexV(wlock); //SDL_mutexV(lock);
std::getline(std::cin, output); std::getline(std::cin, output);
//SDL_mutexP(wlock); //SDL_mutexP(lock);
return output.size(); return output.size();
} }
else else
@ -283,7 +283,7 @@ namespace DFHack
if(state == con_lineedit) if(state == con_lineedit)
return -1; return -1;
state = con_lineedit; state = con_lineedit;
count = prompt_loop(); count = prompt_loop(lock);
state = con_unclaimed; state = con_unclaimed;
disable_raw(); disable_raw();
print("\n"); print("\n");
@ -376,7 +376,7 @@ namespace DFHack
if (::write(STDIN_FILENO,seq,strlen(seq)) == -1) return; if (::write(STDIN_FILENO,seq,strlen(seq)) == -1) return;
} }
int prompt_loop() int prompt_loop(SDL::Mutex * lock)
{ {
int fd = STDIN_FILENO; int fd = STDIN_FILENO;
size_t plen = prompt.size(); size_t plen = prompt.size();
@ -393,9 +393,9 @@ namespace DFHack
char c; char c;
int nread; int nread;
char seq[2], seq2; char seq[2], seq2;
SDL_mutexV(wlock); SDL_mutexV(lock);
nread = ::read(fd,&c,1); nread = ::read(fd,&c,1);
SDL_mutexP(wlock); SDL_mutexP(lock);
if (nread <= 0) return raw_buffer.size(); if (nread <= 0) return raw_buffer.size();
/* Only autocomplete when the callback is set. It returns < 0 when /* Only autocomplete when the callback is set. It returns < 0 when
@ -439,13 +439,13 @@ namespace DFHack
} }
break; break;
case 27: // escape sequence case 27: // escape sequence
SDL_mutexV(wlock); SDL_mutexV(lock);
if (::read(fd,seq,2) == -1) if (::read(fd,seq,2) == -1)
{ {
SDL_mutexP(wlock); SDL_mutexP(lock);
break; break;
} }
SDL_mutexP(wlock); SDL_mutexP(lock);
if(seq[0] == '[') if(seq[0] == '[')
{ {
if (seq[1] == 'D') if (seq[1] == 'D')
@ -507,13 +507,13 @@ namespace DFHack
else if (seq[1] > '0' && seq[1] < '7') else if (seq[1] > '0' && seq[1] < '7')
{ {
// extended escape // extended escape
SDL_mutexV(wlock); SDL_mutexV(lock);
if (::read(fd,&seq2,1) == -1) if (::read(fd,&seq2,1) == -1)
{ {
SDL_mutexP(wlock); SDL_mutexP(lock);
break; break;
} }
SDL_mutexP(wlock); SDL_mutexP(lock);
if (seq[1] == '3' && seq2 == '~' ) if (seq[1] == '3' && seq2 == '~' )
{ {
// delete // delete
@ -588,17 +588,22 @@ namespace DFHack
std::string prompt; // current prompt string std::string prompt; // current prompt string
std::string raw_buffer; // current raw mode buffer std::string raw_buffer; // current raw mode buffer
int raw_cursor; // cursor position in the buffer int raw_cursor; // cursor position in the buffer
// locks
SDL::Mutex *wlock;
}; };
} }
Console::Console():std::ostream(0), std::ios(0) Console::Console():std::ostream(0), std::ios(0)
{ {
d = 0; d = 0;
inited = false;
// we can't create the mutex at this time. the SDL functions aren't hooked yet.
wlock = 0;
} }
Console::~Console() Console::~Console()
{ {
if(inited)
shutdown();
if(wlock)
SDL_DestroyMutex(wlock);
if(d) if(d)
delete d; delete d;
} }
@ -608,100 +613,133 @@ bool Console::init(void)
d = new Private(); d = new Private();
// make our own weird streams so our IO isn't redirected // make our own weird streams so our IO isn't redirected
d->dfout_C = fopen("/dev/tty", "w"); d->dfout_C = fopen("/dev/tty", "w");
d->wlock = SDL_CreateMutex(); wlock = SDL_CreateMutex();
rdbuf(d); rdbuf(d);
std::cin.tie(this); std::cin.tie(this);
clear(); clear();
d->supported_terminal = !isUnsupportedTerm() && isatty(STDIN_FILENO); d->supported_terminal = !isUnsupportedTerm() && isatty(STDIN_FILENO);
inited = true;
} }
bool Console::shutdown(void) bool Console::shutdown(void)
{ {
SDL_mutexP(wlock);
if(d->rawmode) if(d->rawmode)
d->disable_raw(); d->disable_raw();
print("\n"); print("\n");
inited = false;
SDL_mutexV(wlock);
return true;
} }
int Console::print( const char* format, ... ) int Console::print( const char* format, ... )
{ {
va_list args; va_list args;
SDL_mutexP(d->wlock); SDL_mutexP(wlock);
va_start( args, format ); int ret;
int ret = d->vprint(format, args); if(!inited) ret = -1;
va_end(args); else
SDL_mutexV(d->wlock); {
va_start( args, format );
ret = d->vprint(format, args);
va_end(args);
}
SDL_mutexV(wlock);
return ret; return ret;
} }
int Console::printerr( const char* format, ... ) int Console::printerr( const char* format, ... )
{ {
va_list args; va_list args;
SDL_mutexP(d->wlock); SDL_mutexP(wlock);
va_start( args, format ); int ret;
int ret = d->vprinterr(format, args); if(!inited) ret = -1;
va_end(args); else
SDL_mutexV(d->wlock); {
va_start( args, format );
ret = d->vprinterr(format, args);
va_end(args);
}
SDL_mutexV(wlock);
return ret; return ret;
} }
int Console::get_columns(void) int Console::get_columns(void)
{ {
return d->get_columns(); SDL_mutexP(wlock);
int ret = -1;
if(inited)
ret = d->get_columns();
SDL_mutexV(wlock);
return ret;
} }
int Console::get_rows(void) int Console::get_rows(void)
{ {
return d->get_rows(); SDL_mutexP(wlock);
int ret = -1;
if(inited)
ret = d->get_rows();
SDL_mutexV(wlock);
return ret;
} }
void Console::clear() void Console::clear()
{ {
SDL_mutexP(d->wlock); SDL_mutexP(wlock);
d->clear(); if(inited)
SDL_mutexV(d->wlock); d->clear();
SDL_mutexV(wlock);
} }
void Console::gotoxy(int x, int y) void Console::gotoxy(int x, int y)
{ {
SDL_mutexP(d->wlock); SDL_mutexP(wlock);
d->gotoxy(x,y); if(inited)
SDL_mutexV(d->wlock); d->gotoxy(x,y);
SDL_mutexV(wlock);
} }
void Console::color(color_value index) void Console::color(color_value index)
{ {
SDL_mutexP(d->wlock); SDL_mutexP(wlock);
d->color(index); if(inited)
SDL_mutexV(d->wlock); d->color(index);
SDL_mutexV(wlock);
} }
void Console::reset_color( void ) void Console::reset_color( void )
{ {
SDL_mutexP(d->wlock); SDL_mutexP(wlock);
d->reset_color(); if(inited)
SDL_mutexV(d->wlock); d->reset_color();
SDL_mutexV(wlock);
} }
void Console::cursor(bool enable) void Console::cursor(bool enable)
{ {
SDL_mutexP(d->wlock); SDL_mutexP(wlock);
d->cursor(enable); if(inited)
SDL_mutexV(d->wlock); d->cursor(enable);
SDL_mutexV(wlock);
} }
// push to front, remove from back if we are above maximum. ignore immediate duplicates // push to front, remove from back if we are above maximum. ignore immediate duplicates
void Console::history_add(const std::string & command) void Console::history_add(const std::string & command)
{ {
SDL_mutexP(d->wlock); SDL_mutexP(wlock);
d->history_add(command); if(inited)
SDL_mutexV(d->wlock); d->history_add(command);
SDL_mutexV(wlock);
} }
int Console::lineedit(const std::string & prompt, std::string & output) int Console::lineedit(const std::string & prompt, std::string & output)
{ {
SDL_mutexP(d->wlock); SDL_mutexP(wlock);
int ret = d->lineedit(prompt,output); int ret = -2;
SDL_mutexV(d->wlock); if(inited)
ret = d->lineedit(prompt,output,wlock);
SDL_mutexV(wlock);
return ret; return ret;
} }

@ -247,7 +247,7 @@ namespace DFHack
SetConsoleCursorPosition(console_out, inf.dwCursorPosition); SetConsoleCursorPosition(console_out, inf.dwCursorPosition);
} }
int prompt_loop() int prompt_loop(SDL::Mutex * lock)
{ {
raw_buffer.clear(); // make sure the buffer is empty! raw_buffer.clear(); // make sure the buffer is empty!
size_t plen = prompt.size(); size_t plen = prompt.size();
@ -269,9 +269,9 @@ namespace DFHack
{ {
INPUT_RECORD rec; INPUT_RECORD rec;
DWORD count; DWORD count;
SDL_mutexV(wlock); SDL_mutexV(lock);
ReadConsoleInputA(console_in, &rec, 1, &count); ReadConsoleInputA(console_in, &rec, 1, &count);
SDL_mutexP(wlock); SDL_mutexP(lock);
if (rec.EventType != KEY_EVENT || !rec.Event.KeyEvent.bKeyDown) if (rec.EventType != KEY_EVENT || !rec.Event.KeyEvent.bKeyDown)
continue; continue;
switch (rec.Event.KeyEvent.wVirtualKeyCode) switch (rec.Event.KeyEvent.wVirtualKeyCode)
@ -356,13 +356,13 @@ namespace DFHack
} }
} }
} }
int lineedit(const std::string & prompt, std::string & output) int lineedit(const std::string & prompt, std::string & output, SDL::Mutex*lock)
{ {
output.clear(); output.clear();
int count; int count;
state = con_lineedit; state = con_lineedit;
this->prompt = prompt; this->prompt = prompt;
count = prompt_loop(); count = prompt_loop(lock);
if(count != -1) if(count != -1)
output = raw_buffer; output = raw_buffer;
state = con_unclaimed; state = con_unclaimed;
@ -398,8 +398,6 @@ namespace DFHack
std::string prompt; // current prompt string std::string prompt; // current prompt string
std::string raw_buffer; // current raw mode buffer std::string raw_buffer; // current raw mode buffer
int raw_cursor; // cursor position in the buffer int raw_cursor; // cursor position in the buffer
// locks
SDL::Mutex *wlock;
}; };
} }
@ -407,6 +405,8 @@ namespace DFHack
Console::Console():std::ostream(0), std::ios(0) Console::Console():std::ostream(0), std::ios(0)
{ {
d = 0; d = 0;
wlock = 0;
inited = false;
} }
Console::~Console() Console::~Console()
@ -425,7 +425,7 @@ bool Console::init(void)
// Allocate a console! // Allocate a console!
AllocConsole(); AllocConsole();
d->ConsoleWindow = GetConsoleWindow(); d->ConsoleWindow = GetConsoleWindow();
d->wlock = SDL_CreateMutex(); wlock = SDL_CreateMutex();
HMENU hm = GetSystemMenu(d->ConsoleWindow,false); HMENU hm = GetSystemMenu(d->ConsoleWindow,false);
DeleteMenu(hm, SC_CLOSE, MF_BYCOMMAND); DeleteMenu(hm, SC_CLOSE, MF_BYCOMMAND);
@ -459,95 +459,126 @@ bool Console::init(void)
rdbuf(d); rdbuf(d);
std::cin.tie(this); std::cin.tie(this);
clear(); clear();
inited = true;
return true; return true;
} }
// FIXME: looks awfully empty, doesn't it? // FIXME: looks awfully empty, doesn't it?
bool Console::shutdown(void) bool Console::shutdown(void)
{ {
SDL_mutexP(wlock);
FreeConsole(); FreeConsole();
inited = false;
SDL_mutexV(wlock);
return true; return true;
} }
int Console::print( const char* format, ... ) int Console::print( const char* format, ... )
{ {
va_list args; va_list args;
SDL_mutexP(d->wlock); SDL_mutexP(wlock);
va_start( args, format ); int ret;
int ret = d->vprint(format, args); if(!inited) ret = -1;
va_end(args); else
SDL_mutexV(d->wlock); {
va_start( args, format );
ret = d->vprint(format, args);
va_end(args);
}
SDL_mutexV(wlock);
return ret; return ret;
} }
int Console::printerr( const char* format, ... ) int Console::printerr( const char* format, ... )
{ {
va_list args; va_list args;
SDL_mutexP(d->wlock); SDL_mutexP(wlock);
va_start( args, format ); int ret;
int ret = d->vprinterr(format, args); if(!inited) ret = -1;
va_end(args); else
SDL_mutexV(d->wlock); {
va_start( args, format );
ret = d->vprinterr(format, args);
va_end(args);
}
SDL_mutexV(wlock);
return ret; return ret;
} }
int Console::get_columns(void) int Console::get_columns(void)
{ {
return d->get_columns(); SDL_mutexP(wlock);
int ret = -1;
if(inited)
ret = d->get_columns();
SDL_mutexV(wlock);
return ret;
} }
int Console::get_rows(void) int Console::get_rows(void)
{ {
return d->get_rows(); SDL_mutexP(wlock);
int ret = -1;
if(inited)
ret = d->get_rows();
SDL_mutexV(wlock);
return ret;
} }
void Console::clear() void Console::clear()
{ {
SDL_mutexP(d->wlock); SDL_mutexP(wlock);
d->clear(); if(inited)
SDL_mutexV(d->wlock); d->clear();
SDL_mutexV(wlock);
} }
void Console::gotoxy(int x, int y) void Console::gotoxy(int x, int y)
{ {
SDL_mutexP(d->wlock); SDL_mutexP(wlock);
d->gotoxy(x,y); if(inited)
SDL_mutexV(d->wlock); d->gotoxy(x,y);
SDL_mutexV(wlock);
} }
void Console::color(color_value index) void Console::color(color_value index)
{ {
SDL_mutexP(d->wlock); SDL_mutexP(wlock);
d->color(index); if(inited)
SDL_mutexV(d->wlock); d->color(index);
SDL_mutexV(wlock);
} }
void Console::reset_color( void ) void Console::reset_color( void )
{ {
SDL_mutexP(d->wlock); SDL_mutexP(wlock);
d->reset_color(); if(inited)
SDL_mutexV(d->wlock); d->reset_color();
SDL_mutexV(wlock);
} }
void Console::cursor(bool enable) void Console::cursor(bool enable)
{ {
SDL_mutexP(d->wlock); SDL_mutexP(wlock);
d->cursor(enable); if(inited)
SDL_mutexV(d->wlock); d->cursor(enable);
SDL_mutexV(wlock);
} }
// push to front, remove from back if we are above maximum. ignore immediate duplicates // push to front, remove from back if we are above maximum. ignore immediate duplicates
void Console::history_add(const std::string & command) void Console::history_add(const std::string & command)
{ {
SDL_mutexP(d->wlock); SDL_mutexP(wlock);
d->history_add(command); if(inited)
SDL_mutexV(d->wlock); d->history_add(command);
SDL_mutexV(wlock);
} }
int Console::lineedit(const std::string & prompt, std::string & output) int Console::lineedit(const std::string & prompt, std::string & output)
{ {
SDL_mutexP(d->wlock); SDL_mutexP(wlock);
int ret = d->lineedit(prompt,output); int ret = -2;
SDL_mutexV(d->wlock); if(inited)
ret = d->lineedit(prompt,output,wlock);
SDL_mutexV(wlock);
return ret; return ret;
} }

@ -78,6 +78,8 @@ DFhackCExport int SDL_NumJoysticks(void)
{ {
DFHack::Core & c = DFHack::Core::getInstance(); DFHack::Core & c = DFHack::Core::getInstance();
// the 'inited' variable should be normally protected by a lock. It isn't // the 'inited' variable should be normally protected by a lock. It isn't
// this is harmless enough. only thing this can cause is a slight delay before
// DF input events start to be processed by Core
int ret = c.Update(); int ret = c.Update();
if(ret == 0) if(ret == 0)
inited = true; inited = true;

@ -26,6 +26,7 @@ distribution.
#include "dfhack/Pragma.h" #include "dfhack/Pragma.h"
#include "dfhack/Export.h" #include "dfhack/Export.h"
#include <ostream> #include <ostream>
#include "FakeSDL.h"
namespace DFHack namespace DFHack
{ {
class Private; class Private;
@ -92,5 +93,7 @@ namespace DFHack
void history_clear(); void history_clear();
private: private:
Private * d; Private * d;
SDL::Mutex * wlock;
bool inited;
}; };
} }

@ -48,7 +48,9 @@ DFhackCExport command_result plugin_onupdate ( Core * c )
if(timering == true) if(timering == true)
{ {
uint64_t time2 = GetTimeMs64(); uint64_t time2 = GetTimeMs64();
// harmless potential data race here...
uint64_t delta = time2-timeLast; uint64_t delta = time2-timeLast;
// harmless potential data race here...
timeLast = time2; timeLast = time2;
c->con.print("Time delta = %d ms\n", delta); c->con.print("Time delta = %d ms\n", delta);
} }
@ -67,6 +69,7 @@ DFhackCExport command_result ktimer (Core * c, vector <string> & parameters)
c->Resume(); c->Resume();
uint64_t timeend = GetTimeMs64(); uint64_t timeend = GetTimeMs64();
c->con.print("Time to suspend = %d ms\n",timeend - timestart); c->con.print("Time to suspend = %d ms\n",timeend - timestart);
// harmless potential data race here...
timeLast = timeend; timeLast = timeend;
timering = true; timering = true;
return CR_OK; return CR_OK;