Cygwin: console: Make I/O functions thread-safe
- POSIX states I/O functions shall be thread-safe, however, cygwin console I/O functions were not. This patch makes console I/O functions thread-safe.
This commit is contained in:
parent
8382778cdb
commit
f4b47827cf
@ -1698,6 +1698,12 @@ class fhandler_serial: public fhandler_base
|
||||
}
|
||||
};
|
||||
|
||||
#define acquire_input_mutex(ms) \
|
||||
__acquire_input_mutex (__PRETTY_FUNCTION__, __LINE__, ms)
|
||||
|
||||
#define release_input_mutex() \
|
||||
__release_input_mutex (__PRETTY_FUNCTION__, __LINE__)
|
||||
|
||||
#define acquire_output_mutex(ms) \
|
||||
__acquire_output_mutex (__PRETTY_FUNCTION__, __LINE__, ms)
|
||||
|
||||
@ -1897,6 +1903,7 @@ private:
|
||||
static const unsigned MAX_WRITE_CHARS;
|
||||
static console_state *shared_console_info;
|
||||
static bool invisible_console;
|
||||
HANDLE input_mutex, output_mutex;
|
||||
|
||||
/* Used when we encounter a truncated multi-byte sequence. The
|
||||
lead bytes are stored here and revisited in the next write call. */
|
||||
@ -1966,8 +1973,11 @@ private:
|
||||
bool focus_aware () {return shared_console_info->con.use_focus;}
|
||||
bool get_cons_readahead_valid ()
|
||||
{
|
||||
return shared_console_info->con.cons_rapoi != NULL &&
|
||||
acquire_input_mutex (INFINITE);
|
||||
bool ret = shared_console_info->con.cons_rapoi != NULL &&
|
||||
*shared_console_info->con.cons_rapoi;
|
||||
release_input_mutex ();
|
||||
return ret;
|
||||
}
|
||||
|
||||
select_record *select_read (select_stuff *);
|
||||
@ -2002,6 +2012,12 @@ private:
|
||||
return fh;
|
||||
}
|
||||
input_states process_input_message ();
|
||||
void setup_io_mutex (void);
|
||||
DWORD __acquire_input_mutex (const char *fn, int ln, DWORD ms);
|
||||
void __release_input_mutex (const char *fn, int ln);
|
||||
DWORD __acquire_output_mutex (const char *fn, int ln, DWORD ms);
|
||||
void __release_output_mutex (const char *fn, int ln);
|
||||
|
||||
friend tty_min * tty_list::get_cttyp ();
|
||||
};
|
||||
|
||||
|
@ -232,6 +232,45 @@ tty_list::get_cttyp ()
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
fhandler_console::setup_io_mutex (void)
|
||||
{
|
||||
char buf[MAX_PATH];
|
||||
DWORD res;
|
||||
|
||||
res = WAIT_FAILED;
|
||||
if (!input_mutex || WAIT_FAILED == (res = acquire_input_mutex (0)))
|
||||
{
|
||||
shared_name (buf, "cygcons.input.mutex", get_minor ());
|
||||
input_mutex = OpenMutex (MAXIMUM_ALLOWED, TRUE, buf);
|
||||
if (!input_mutex)
|
||||
input_mutex = CreateMutex (&sec_none, FALSE, buf);
|
||||
if (!input_mutex)
|
||||
{
|
||||
__seterrno ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (res == WAIT_OBJECT_0)
|
||||
release_input_mutex ();
|
||||
|
||||
res = WAIT_FAILED;
|
||||
if (!output_mutex || WAIT_FAILED == (res = acquire_output_mutex (0)))
|
||||
{
|
||||
shared_name (buf, "cygcons.output.mutex", get_minor ());
|
||||
output_mutex = OpenMutex (MAXIMUM_ALLOWED, TRUE, buf);
|
||||
if (!output_mutex)
|
||||
output_mutex = CreateMutex (&sec_none, FALSE, buf);
|
||||
if (!output_mutex)
|
||||
{
|
||||
__seterrno ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (res == WAIT_OBJECT_0)
|
||||
release_output_mutex ();
|
||||
}
|
||||
|
||||
inline DWORD
|
||||
dev_console::con_to_str (char *d, int dlen, WCHAR w)
|
||||
{
|
||||
@ -362,7 +401,9 @@ fhandler_console::read (void *pv, size_t& buflen)
|
||||
#define buf ((char *) pv)
|
||||
|
||||
int ret;
|
||||
acquire_input_mutex (INFINITE);
|
||||
ret = process_input_message ();
|
||||
release_input_mutex ();
|
||||
switch (ret)
|
||||
{
|
||||
case input_error:
|
||||
@ -382,6 +423,7 @@ fhandler_console::read (void *pv, size_t& buflen)
|
||||
}
|
||||
|
||||
/* Check console read-ahead buffer filled from terminal requests */
|
||||
acquire_input_mutex (INFINITE);
|
||||
while (con.cons_rapoi && *con.cons_rapoi && buflen)
|
||||
{
|
||||
buf[copied_chars++] = *con.cons_rapoi++;
|
||||
@ -393,6 +435,7 @@ fhandler_console::read (void *pv, size_t& buflen)
|
||||
|
||||
if (!ralen)
|
||||
input_ready = false;
|
||||
release_input_mutex ();
|
||||
|
||||
#undef buf
|
||||
|
||||
@ -903,6 +946,8 @@ fhandler_console::open (int flags, mode_t)
|
||||
}
|
||||
set_output_handle (h);
|
||||
|
||||
setup_io_mutex ();
|
||||
|
||||
if (con.fillin (get_output_handle ()))
|
||||
{
|
||||
con.current_win32_attr = con.b.wAttributes;
|
||||
@ -953,6 +998,11 @@ fhandler_console::close ()
|
||||
{
|
||||
debug_printf ("closing: %p, %p", get_handle (), get_output_handle ());
|
||||
|
||||
CloseHandle (input_mutex);
|
||||
input_mutex = NULL;
|
||||
CloseHandle (output_mutex);
|
||||
output_mutex = NULL;
|
||||
|
||||
if (shared_console_info && getpid () == con.owner &&
|
||||
wincap.has_con_24bit_colors ())
|
||||
{
|
||||
@ -980,6 +1030,7 @@ fhandler_console::ioctl (unsigned int cmd, void *arg)
|
||||
int res = fhandler_termios::ioctl (cmd, arg);
|
||||
if (res <= 0)
|
||||
return res;
|
||||
acquire_output_mutex (INFINITE);
|
||||
switch (cmd)
|
||||
{
|
||||
case TIOCGWINSZ:
|
||||
@ -995,20 +1046,25 @@ fhandler_console::ioctl (unsigned int cmd, void *arg)
|
||||
syscall_printf ("WINSZ: (row=%d,col=%d)",
|
||||
((struct winsize *) arg)->ws_row,
|
||||
((struct winsize *) arg)->ws_col);
|
||||
release_output_mutex ();
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
syscall_printf ("WINSZ failed");
|
||||
__seterrno ();
|
||||
release_output_mutex ();
|
||||
return -1;
|
||||
}
|
||||
release_output_mutex ();
|
||||
return 0;
|
||||
case TIOCSWINSZ:
|
||||
bg_check (SIGTTOU);
|
||||
release_output_mutex ();
|
||||
return 0;
|
||||
case KDGKBMETA:
|
||||
*(int *) arg = (con.metabit) ? K_METABIT : K_ESCPREFIX;
|
||||
release_output_mutex ();
|
||||
return 0;
|
||||
case KDSKBMETA:
|
||||
if ((intptr_t) arg == K_METABIT)
|
||||
@ -1018,16 +1074,20 @@ fhandler_console::ioctl (unsigned int cmd, void *arg)
|
||||
else
|
||||
{
|
||||
set_errno (EINVAL);
|
||||
release_output_mutex ();
|
||||
return -1;
|
||||
}
|
||||
release_output_mutex ();
|
||||
return 0;
|
||||
case TIOCLINUX:
|
||||
if (*(unsigned char *) arg == 6)
|
||||
{
|
||||
*(unsigned char *) arg = (unsigned char) con.nModifiers;
|
||||
release_output_mutex ();
|
||||
return 0;
|
||||
}
|
||||
set_errno (EINVAL);
|
||||
release_output_mutex ();
|
||||
return -1;
|
||||
case FIONREAD:
|
||||
{
|
||||
@ -1040,17 +1100,20 @@ fhandler_console::ioctl (unsigned int cmd, void *arg)
|
||||
if (!PeekConsoleInputW (get_handle (), inp, INREC_SIZE, &n))
|
||||
{
|
||||
set_errno (EINVAL);
|
||||
release_output_mutex ();
|
||||
return -1;
|
||||
}
|
||||
while (n-- > 0)
|
||||
if (inp[n].EventType == KEY_EVENT && inp[n].Event.KeyEvent.bKeyDown)
|
||||
++ret;
|
||||
*(int *) arg = ret;
|
||||
release_output_mutex ();
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
release_output_mutex ();
|
||||
return fhandler_base::ioctl (cmd, arg);
|
||||
}
|
||||
|
||||
@ -1075,6 +1138,7 @@ fhandler_console::output_tcsetattr (int, struct termios const *t)
|
||||
{
|
||||
/* All the output bits we can ignore */
|
||||
|
||||
acquire_output_mutex (INFINITE);
|
||||
DWORD flags = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
|
||||
/* If system has 24 bit color capability, use xterm compatible mode. */
|
||||
if (wincap.has_con_24bit_colors ())
|
||||
@ -1087,6 +1151,7 @@ fhandler_console::output_tcsetattr (int, struct termios const *t)
|
||||
int res = SetConsoleMode (get_output_handle (), flags) ? 0 : -1;
|
||||
if (res)
|
||||
__seterrno_from_win_error (GetLastError ());
|
||||
release_output_mutex ();
|
||||
syscall_printf ("%d = tcsetattr(,%p) (ENABLE FLAGS %y) (lflag %y oflag %y)",
|
||||
res, t, flags, t->c_lflag, t->c_oflag);
|
||||
return res;
|
||||
@ -1097,6 +1162,7 @@ fhandler_console::input_tcsetattr (int, struct termios const *t)
|
||||
{
|
||||
/* Ignore the optional_actions stuff, since all output is emitted
|
||||
instantly */
|
||||
acquire_input_mutex (INFINITE);
|
||||
|
||||
DWORD oflags;
|
||||
|
||||
@ -1158,6 +1224,7 @@ fhandler_console::input_tcsetattr (int, struct termios const *t)
|
||||
}
|
||||
|
||||
get_ttyp ()->rstcons (false);
|
||||
release_input_mutex ();
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -1210,7 +1277,8 @@ fhandler_console::tcgetattr (struct termios *t)
|
||||
}
|
||||
|
||||
fhandler_console::fhandler_console (fh_devices unit) :
|
||||
fhandler_termios (), input_ready (false)
|
||||
fhandler_termios (), input_ready (false),
|
||||
input_mutex (NULL), output_mutex (NULL)
|
||||
{
|
||||
if (unit > 0)
|
||||
dev ().parse (unit);
|
||||
@ -2132,9 +2200,11 @@ fhandler_console::char_command (char c)
|
||||
fhandler_console object associated with standard input.
|
||||
So puts_readahead does not work.
|
||||
Use a common console read-ahead buffer instead. */
|
||||
acquire_input_mutex (INFINITE);
|
||||
con.cons_rapoi = NULL;
|
||||
strcpy (con.cons_rabuf, buf);
|
||||
con.cons_rapoi = con.cons_rabuf;
|
||||
release_input_mutex ();
|
||||
/* Wake up read() or select() by sending a message
|
||||
which has no effect */
|
||||
PostMessageW (GetConsoleWindow (), WM_SETFOCUS, 0, 0);
|
||||
@ -2147,9 +2217,11 @@ fhandler_console::char_command (char c)
|
||||
y -= con.b.srWindow.Top;
|
||||
/* x -= con.b.srWindow.Left; // not available yet */
|
||||
__small_sprintf (buf, "\033[%d;%dR", y + 1, x + 1);
|
||||
acquire_input_mutex (INFINITE);
|
||||
con.cons_rapoi = NULL;
|
||||
strcpy (con.cons_rabuf, buf);
|
||||
con.cons_rapoi = con.cons_rabuf;
|
||||
release_input_mutex ();
|
||||
/* Wake up read() or select() by sending a message
|
||||
which has no effect */
|
||||
PostMessageW (GetConsoleWindow (), WM_SETFOCUS, 0, 0);
|
||||
@ -2487,6 +2559,7 @@ fhandler_console::write (const void *vsrc, size_t len)
|
||||
return (ssize_t) bg;
|
||||
|
||||
push_process_state process_state (PID_TTYOU);
|
||||
acquire_output_mutex (INFINITE);
|
||||
|
||||
/* Run and check for ansi sequences */
|
||||
unsigned const char *src = (unsigned char *) vsrc;
|
||||
@ -2507,7 +2580,10 @@ fhandler_console::write (const void *vsrc, size_t len)
|
||||
case normal:
|
||||
src = write_normal (src, end);
|
||||
if (!src) /* write_normal failed */
|
||||
return -1;
|
||||
{
|
||||
release_output_mutex ();
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case gotesc:
|
||||
if (*src == '[') /* CSI Control Sequence Introducer */
|
||||
@ -2676,6 +2752,7 @@ fhandler_console::write (const void *vsrc, size_t len)
|
||||
break;
|
||||
}
|
||||
}
|
||||
release_output_mutex ();
|
||||
|
||||
syscall_printf ("%ld = fhandler_console::write(...)", len);
|
||||
|
||||
@ -2803,6 +2880,7 @@ void
|
||||
fhandler_console::fixup_after_fork_exec (bool execing)
|
||||
{
|
||||
set_unit ();
|
||||
setup_io_mutex ();
|
||||
}
|
||||
|
||||
// #define WINSTA_ACCESS (WINSTA_READATTRIBUTES | STANDARD_RIGHTS_READ | STANDARD_RIGHTS_WRITE | WINSTA_CREATEDESKTOP | WINSTA_EXITWINDOWS)
|
||||
@ -2986,3 +3064,57 @@ fhandler_console::need_invisible ()
|
||||
debug_printf ("invisible_console %d", invisible_console);
|
||||
return b;
|
||||
}
|
||||
|
||||
DWORD
|
||||
fhandler_console::__acquire_input_mutex (const char *fn, int ln, DWORD ms)
|
||||
{
|
||||
#ifdef DEBUGGING
|
||||
strace.prntf (_STRACE_TERMIOS, fn, "(%d): trying to get input_mutex", ln);
|
||||
#endif
|
||||
DWORD res = WaitForSingleObject (input_mutex, ms);
|
||||
if (res != WAIT_OBJECT_0)
|
||||
strace.prntf (_STRACE_TERMIOS, fn,
|
||||
"(%d): Failed to acquire input_mutex %08x",
|
||||
ln, GetLastError ());
|
||||
#ifdef DEBUGGING
|
||||
else
|
||||
strace.prntf (_STRACE_TERMIOS, fn, "(%d): got input_mutex", ln);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
fhandler_console::__release_input_mutex (const char *fn, int ln)
|
||||
{
|
||||
ReleaseMutex (input_mutex);
|
||||
#ifdef DEBUGGING
|
||||
strace.prntf (_STRACE_TERMIOS, fn, "(%d): release input_mutex", ln);
|
||||
#endif
|
||||
}
|
||||
|
||||
DWORD
|
||||
fhandler_console::__acquire_output_mutex (const char *fn, int ln, DWORD ms)
|
||||
{
|
||||
#ifdef DEBUGGING
|
||||
strace.prntf (_STRACE_TERMIOS, fn, "(%d): trying to get output_mutex", ln);
|
||||
#endif
|
||||
DWORD res = WaitForSingleObject (output_mutex, ms);
|
||||
if (res != WAIT_OBJECT_0)
|
||||
strace.prntf (_STRACE_TERMIOS, fn,
|
||||
"(%d): Failed to acquire output_mutex %08x",
|
||||
ln, GetLastError ());
|
||||
#ifdef DEBUGGING
|
||||
else
|
||||
strace.prntf (_STRACE_TERMIOS, fn, "(%d): got output_mutex", ln);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
fhandler_console::__release_output_mutex (const char *fn, int ln)
|
||||
{
|
||||
ReleaseMutex (output_mutex);
|
||||
#ifdef DEBUGGING
|
||||
strace.prntf (_STRACE_TERMIOS, fn, "(%d): release output_mutex", ln);
|
||||
#endif
|
||||
}
|
||||
|
@ -1039,15 +1039,20 @@ peek_console (select_record *me, bool)
|
||||
set_handle_or_return_if_not_open (h, me);
|
||||
|
||||
while (!fh->input_ready && !fh->get_cons_readahead_valid ())
|
||||
if (fh->bg_check (SIGTTIN, true) <= bg_eof)
|
||||
return me->read_ready = true;
|
||||
else if (!PeekConsoleInputW (h, &irec, 1, &events_read) || !events_read)
|
||||
break;
|
||||
else if (fhandler_console::input_winch == fh->process_input_message ())
|
||||
{
|
||||
set_sig_errno (EINTR);
|
||||
return -1;
|
||||
}
|
||||
{
|
||||
if (fh->bg_check (SIGTTIN, true) <= bg_eof)
|
||||
return me->read_ready = true;
|
||||
else if (!PeekConsoleInputW (h, &irec, 1, &events_read) || !events_read)
|
||||
break;
|
||||
fh->acquire_input_mutex (INFINITE);
|
||||
if (fhandler_console::input_winch == fh->process_input_message ())
|
||||
{
|
||||
set_sig_errno (EINTR);
|
||||
fh->release_input_mutex ();
|
||||
return -1;
|
||||
}
|
||||
fh->release_input_mutex ();
|
||||
}
|
||||
if (fh->input_ready || fh->get_cons_readahead_valid ())
|
||||
return me->read_ready = true;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user