diff options
Diffstat (limited to 'winsup/cygwin/fhandler/console.cc')
-rw-r--r-- | winsup/cygwin/fhandler/console.cc | 162 |
1 files changed, 112 insertions, 50 deletions
diff --git a/winsup/cygwin/fhandler/console.cc b/winsup/cygwin/fhandler/console.cc index 1c0d5c8..d4c3f10 100644 --- a/winsup/cygwin/fhandler/console.cc +++ b/winsup/cygwin/fhandler/console.cc @@ -33,6 +33,7 @@ details. */ #include "child_info.h" #include "cygwait.h" #include "winf.h" +#include "psapi.h" /* Don't make this bigger than NT_MAX_PATH as long as the temporary buffer is allocated using tmp_pathbuf!!! */ @@ -48,6 +49,9 @@ details. */ con.b.srWindow.Top + con.scroll_region.Bottom) #define con_is_legacy (shared_console_info[unit] && con.is_legacy) +static HANDLE NO_COPY shared_info_mutex; +static int NO_COPY shared_info_state[MAX_CONS_DEV]; + #define CONS_THREAD_SYNC "cygcons.thread_sync" static bool NO_COPY master_thread_started = false; @@ -224,44 +228,52 @@ fhandler_console::open_shared_console (HWND hw, HANDLE& h, bool& created) return res; } -BOOL CALLBACK -fhandler_console::enum_windows (HWND hw, LPARAM lp) +fhandler_console::console_unit::console_unit (int n0, HANDLE *input_mutex) : + n (-1) { - console_unit *this1 = (console_unit *) lp; - HANDLE h = NULL; - fhandler_console::console_state *cs; - if ((cs = fhandler_console::open_shared_console (hw, h))) + char buf[MAX_PATH]; + for (int i = max(0, n0); i < MAX_CONS_DEV; i++) { - CloseHandle (h); - if (major (cs->tty_min_state.getntty ()) == DEV_CONS_MAJOR) - this1->bitmask |= 1UL << minor (cs->tty_min_state.getntty ()); - if (this1->n == minor (cs->tty_min_state.getntty ())) + shared_name (buf, "cygcons.input.mutex", i); + SetLastError (ERROR_SUCCESS); + HANDLE input_mutex0 = CreateMutex (&sec_none, FALSE, buf); + DWORD err = GetLastError (); + if (err == ERROR_ALREADY_EXISTS || err == ERROR_ACCESS_DENIED) { - this1->shared_console_info = cs; - return FALSE; + if (n0 >= 0) + n = i; } - UnmapViewOfFile ((void *) cs); + else if (n0 == CONS_SCAN_UNUSED) + { + n = i; + if (input_mutex) + *input_mutex = input_mutex0; + break; + } + if (input_mutex0) + CloseHandle (input_mutex0); + if (n0 >= 0) + break; } - else - { /* Only for ConEmu */ - char class_hw[32]; - if (19 == GetClassName (hw, class_hw, sizeof (class_hw)) - && 0 == strcmp (class_hw, "VirtualConsoleClass")) - EnumChildWindows (hw, fhandler_console::enum_windows, lp); + if (n0 == CONS_SCAN_UNUSED && n < 0) + { + __small_sprintf (buf, "console device allocation failure - " + "too many consoles in use, max consoles is %d", + MAX_CONS_DEV); + api_fatal (buf); } - return TRUE; } -fhandler_console::console_unit::console_unit (int n0): - n (n0), bitmask (0), shared_console_info (NULL) +fhandler_console::console_unit::operator console_state * () const { - EnumWindows (fhandler_console::enum_windows, (LPARAM) this); - if (n0 == CONS_SCAN_UNUSED && (n = ffsl (~bitmask) - 1) < 0) - api_fatal (sizeof (bitmask) == 8 ? - "console device allocation failure - " - "too many consoles in use, max consoles is 64" : - "console device allocation failure - " - "too many consoles in use, max consoles is 32"); + if (n < 0 || n >= MAX_CONS_DEV) + return NULL; + HANDLE h = NULL; + fhandler_console::console_state *cs; + HWND hw = cygwin_shared->cons_hwnd[n]; + if ((cs = fhandler_console::open_shared_console (hw, h))) + CloseHandle (h); + return cs; } static DWORD @@ -272,17 +284,23 @@ cons_master_thread (VOID *arg) fhandler_console::handle_set_t handle_set; fh->get_duplicated_handle_set (&handle_set); HANDLE thread_sync_event; - DuplicateHandle (GetCurrentProcess (), fh->thread_sync_event, - GetCurrentProcess (), &thread_sync_event, - 0, FALSE, DUPLICATE_SAME_ACCESS); - SetEvent (thread_sync_event); - master_thread_started = true; - /* Do not touch class members after here because the class instance - may have been destroyed. */ - fhandler_console::cons_master_thread (&handle_set, ttyp); - fhandler_console::close_handle_set (&handle_set); - SetEvent (thread_sync_event); - CloseHandle (thread_sync_event); + if (DuplicateHandle (GetCurrentProcess (), fh->thread_sync_event, + GetCurrentProcess (), &thread_sync_event, + 0, FALSE, DUPLICATE_SAME_ACCESS)) + { + SetEvent (thread_sync_event); + master_thread_started = true; + /* Do not touch class members after here because the class instance + may have been destroyed. */ + fhandler_console::cons_master_thread (&handle_set, ttyp); + fhandler_console::close_handle_set (&handle_set); + SetEvent (thread_sync_event); + CloseHandle (thread_sync_event); + master_thread_started = false; + } + else + debug_printf ("cons_master_thread not started because thread_sync_event " + "could not be duplicated %08x", GetLastError ()); return 0; } @@ -451,6 +469,8 @@ fhandler_console::cons_master_thread (handle_set_t *p, tty *ttyp) case WAIT_CANCELED: break; default: /* Error */ + free (input_rec); + free (input_tmp); ReleaseMutex (p->input_mutex); return; } @@ -650,6 +670,11 @@ fhandler_console::set_unit () else if (myself->ctty != CTTY_UNINITIALIZED) unit = device::minor (myself->ctty); + if (!shared_info_mutex) + shared_info_mutex = CreateMutex (&sec_none_nih, FALSE, NULL); + + WaitForSingleObject (shared_info_mutex, INFINITE); + if (shared_console_info[unit]) ; /* Do nothing */ else if (generic_console @@ -658,7 +683,10 @@ fhandler_console::set_unit () else { if (!generic_console && (dev_t) myself->ctty != get_device ()) - shared_console_info[unit] = console_unit (unit); + { + shared_console_info[unit] = console_unit (unit); + shared_info_state[unit]++; + } if (generic_console || !shared_console_info[unit]) { me = GetConsoleWindow (); @@ -669,10 +697,12 @@ fhandler_console::set_unit () created = true; fhandler_console::console_state *cs = open_shared_console (me, cygheap->console_h, created); + shared_info_state[unit]++; ProtectHandleINH (cygheap->console_h); if (created) { - unit = console_unit (CONS_SCAN_UNUSED); + unit = console_unit (CONS_SCAN_UNUSED, &input_mutex); + cygwin_shared->cons_hwnd[unit] = me; cs->tty_min_state.setntty (DEV_CONS_MAJOR, unit); } else @@ -683,6 +713,8 @@ fhandler_console::set_unit () } } } + ReleaseMutex (shared_info_mutex); + if (shared_console_info[unit]) { devset = (fh_devices) shared_console_info[unit]->tty_min_state.getntty (); @@ -1847,9 +1879,15 @@ fhandler_console::open (int flags, mode_t) char name[MAX_PATH]; shared_name (name, CONS_THREAD_SYNC, get_minor ()); thread_sync_event = CreateEvent(NULL, FALSE, FALSE, name); - new cygthread (::cons_master_thread, this, "consm"); - WaitForSingleObject (thread_sync_event, INFINITE); - CloseHandle (thread_sync_event); + if (thread_sync_event) + { + new cygthread (::cons_master_thread, this, "consm"); + WaitForSingleObject (thread_sync_event, INFINITE); + CloseHandle (thread_sync_event); + } + else + debug_printf ("Failed to create thread_sync_event %08x", + GetLastError ()); } return 1; } @@ -1910,9 +1948,15 @@ fhandler_console::close () char name[MAX_PATH]; shared_name (name, CONS_THREAD_SYNC, get_minor ()); thread_sync_event = OpenEvent (MAXIMUM_ALLOWED, FALSE, name); - con.owner = MAX_PID + 1; - WaitForSingleObject (thread_sync_event, INFINITE); - CloseHandle (thread_sync_event); + if (thread_sync_event) + { + con.owner = MAX_PID + 1; + WaitForSingleObject (thread_sync_event, INFINITE); + CloseHandle (thread_sync_event); + } + else + debug_printf ("Failed to open thread_sync_event %08x", + GetLastError ()); } con.owner = 0; } @@ -1927,7 +1971,23 @@ fhandler_console::close () if (!have_execed && !invisible_console && (!CTTY_IS_VALID (myself->ctty) || get_device () == (dev_t) myself->ctty)) - free_console (); + { + /* ConEmu hack. Detach from ConEmu to unhook console APIs. */ + HMODULE h = GetModuleHandle ("ConEmuHk64.dll"); + if (h) + { + MODULEINFO mi; + if (GetModuleInformation (GetCurrentProcess (), h, &mi, sizeof (mi))) + { + BOOL (*DllMain)(HINSTANCE, DWORD, LPVOID) = + (BOOL (*)(HINSTANCE, DWORD, LPVOID)) mi.EntryPoint; + DllMain (h, DLL_PROCESS_DETACH, NULL); + } + } + + /* Freeing console to detach the process from the console. */ + free_console (); + } release_output_mutex (); @@ -1936,11 +1996,13 @@ fhandler_console::close () CloseHandle (output_mutex); output_mutex = NULL; - if (shared_console_info[unit] && myself->ctty != tc ()->ntty) + WaitForSingleObject (shared_info_mutex, INFINITE); + if (--shared_info_state[unit] == 0 && shared_console_info[unit]) { UnmapViewOfFile ((void *) shared_console_info[unit]); shared_console_info[unit] = NULL; } + ReleaseMutex (shared_info_mutex); return 0; } |