diff options
Diffstat (limited to 'winsup')
38 files changed, 729 insertions, 346 deletions
diff --git a/winsup/cygwin/devices.cc b/winsup/cygwin/devices.cc index d4c003b..6eb6a41 100644 --- a/winsup/cygwin/devices.cc +++ b/winsup/cygwin/devices.cc @@ -83,8 +83,8 @@ exists_console (const device& dev) default: if (dev.get_minor () < MAX_CONS_DEV) { - unsigned long bitmask = fhandler_console::console_unit (CONS_LIST_USED); - return !!(bitmask & (1UL << dev.get_minor ())); + int n = fhandler_console::console_unit (dev.get_minor ()); + return (n == dev.get_minor ()); } return false; } diff --git a/winsup/cygwin/devices.in b/winsup/cygwin/devices.in index a86e501..ea9a70e 100644 --- a/winsup/cygwin/devices.in +++ b/winsup/cygwin/devices.in @@ -79,8 +79,8 @@ exists_console (const device& dev) default: if (dev.get_minor () < MAX_CONS_DEV) { - unsigned long bitmask = fhandler_console::console_unit (CONS_LIST_USED); - return !!(bitmask & (1UL << dev.get_minor ())); + int n = fhandler_console::console_unit (dev.get_minor ()); + return (n == dev.get_minor ()); } return false; } diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index a2a6f9d..3195d57 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -665,7 +665,7 @@ exception::handle (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in, siginfo_t si = {}; si.si_code = SI_KERNEL; /* Coerce win32 value to posix value. */ - switch (e->ExceptionCode) + switch ((NTSTATUS) e->ExceptionCode) { case STATUS_FLOAT_DIVIDE_BY_ZERO: si.si_signo = SIGFPE; @@ -1717,7 +1717,10 @@ _cygtls::call_signal_handler () context, unwind to the caller and in case we're called from sigdelayed, fix the instruction pointer accordingly. */ context.uc_mcontext.ctxflags = CONTEXT_FULL; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" RtlCaptureContext ((PCONTEXT) &context.uc_mcontext); +#pragma GCC diagnostic pop __unwind_single_frame ((PCONTEXT) &context.uc_mcontext); if (stackptr > stack) { diff --git a/winsup/cygwin/fhandler/console.cc b/winsup/cygwin/fhandler/console.cc index 1c0d5c8..2651e49 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; @@ -56,6 +60,10 @@ const unsigned fhandler_console::MAX_WRITE_CHARS = 16384; fhandler_console::console_state NO_COPY *fhandler_console::shared_console_info[MAX_CONS_DEV + 1]; +static bool NO_COPY inside_pcon_checked = false; +static bool NO_COPY inside_pcon = false; +static int NO_COPY parent_pty; + bool NO_COPY fhandler_console::invisible_console; /* con_ra is shared in the same process. @@ -67,37 +75,33 @@ static struct fhandler_base::rabuf_t con_ra; static wchar_t last_char; DWORD -fhandler_console::attach_console (pid_t owner, bool *err) +fhandler_console::attach_console (DWORD owner, bool *err) { DWORD resume_pid = (DWORD) -1; - pinfo p (owner); - if (p) + if (!process_alive (owner)) + return resume_pid; + DWORD attached = + get_console_process_id (owner, true, false, false); + if (!attached) { - DWORD attached = - fhandler_pty_common::get_console_process_id (p->dwProcessId, - true, false, false); - if (!attached) + resume_pid = + get_console_process_id (GetCurrentProcessId (), false, false, false); + FreeConsole (); + BOOL r = AttachConsole (owner); + if (!r) { - resume_pid = - fhandler_pty_common::get_console_process_id (myself->dwProcessId, - false, false, false); - FreeConsole (); - BOOL r = AttachConsole (p->dwProcessId); - if (!r) - { - if (resume_pid) - AttachConsole (resume_pid); - if (err) - *err = true; - return (DWORD) -1; - } + if (resume_pid) + AttachConsole (resume_pid); + if (err) + *err = true; + return (DWORD) -1; } } return resume_pid; } void -fhandler_console::detach_console (DWORD resume_pid, pid_t owner) +fhandler_console::detach_console (DWORD resume_pid, DWORD owner) { if (resume_pid == (DWORD) -1) return; @@ -106,11 +110,11 @@ fhandler_console::detach_console (DWORD resume_pid, pid_t owner) FreeConsole (); AttachConsole (resume_pid); } - else if (myself->pid != owner) + else if (GetCurrentProcessId () != owner) FreeConsole (); } -pid_t +DWORD fhandler_console::get_owner () { return con.owner; @@ -129,14 +133,14 @@ public: { empty (); } - inline void put (HANDLE output_handle, pid_t owner, char x) + inline void put (HANDLE output_handle, DWORD owner, char x) { if (ixput == WPBUF_LEN) send (output_handle, owner); buf[ixput++] = x; } inline void empty () { ixput = 0u; } - inline void send (HANDLE output_handle, pid_t owner) + inline void send (HANDLE output_handle, DWORD owner) { if (!output_handle) { @@ -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; } @@ -377,7 +395,7 @@ fhandler_console::cons_master_thread (handle_set_t *p, tty *ttyp) } }; termios &ti = ttyp->ti; - while (con.owner == myself->pid) + while (con.owner == GetCurrentProcessId ()) { DWORD total_read, n, i; @@ -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,20 +697,24 @@ 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 unit = device::minor (cs->tty_min_state.ntty); shared_console_info[unit] = cs; if (created) - con.owner = myself->pid; + con.owner = GetCurrentProcessId (); } } } + ReleaseMutex (shared_info_mutex); + if (shared_console_info[unit]) { devset = (fh_devices) shared_console_info[unit]->tty_min_state.getntty (); @@ -786,6 +818,7 @@ fhandler_console::set_input_mode (tty::cons_mode m, const termios *t, GetConsoleMode (p->input_handle, &oflags); DWORD flags = oflags & (ENABLE_EXTENDED_FLAGS | ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE); + con.curr_input_mode = m; switch (m) { case tty::restore: @@ -835,6 +868,7 @@ fhandler_console::set_output_mode (tty::cons_mode m, const termios *t, if (con.orig_virtual_terminal_processing_mode) flags |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; WaitForSingleObject (p->output_mutex, mutex_timeout); + con.curr_output_mode = m; switch (m) { case tty::restore: @@ -883,10 +917,10 @@ fhandler_console::cleanup_for_non_cygwin_app (handle_set_t *p) /* conmode can be tty::restore when non-cygwin app is exec'ed from login shell. */ tty::cons_mode conmode = - (con.owner == myself->pid) ? tty::restore : tty::cygwin; + (con.owner == GetCurrentProcessId ()) ? tty::restore : tty::cygwin; set_output_mode (conmode, ti, p); set_input_mode (conmode, ti, p); - set_disable_master_thread (con.owner == myself->pid); + set_disable_master_thread (con.owner == GetCurrentProcessId ()); } /* Return the tty structure associated with a given tty number. If the @@ -999,7 +1033,7 @@ fhandler_console::set_cursor_maybe () /* Workaround for a bug of windows xterm compatible mode. */ /* The horizontal tab positions are broken after resize. */ void -fhandler_console::fix_tab_position (HANDLE h, pid_t owner) +fhandler_console::fix_tab_position (HANDLE h, DWORD owner) { /* Re-setting ENABLE_VIRTUAL_TERMINAL_PROCESSING fixes the tab position. */ @@ -1077,12 +1111,12 @@ fhandler_console::bg_check (int sig, bool dontsignal) /* Setting-up console mode for cygwin app. This is necessary if the cygwin app and other non-cygwin apps are started simultaneously in the same process group. */ - if (sig == SIGTTIN) + if (sig == SIGTTIN && con.curr_input_mode != tty::cygwin) { set_input_mode (tty::cygwin, &tc ()->ti, get_handle_set ()); set_disable_master_thread (false, this); } - if (sig == SIGTTOU) + if (sig == SIGTTOU && con.curr_output_mode != tty::cygwin) set_output_mode (tty::cygwin, &tc ()->ti, get_handle_set ()); return fhandler_termios::bg_check (sig, dontsignal); @@ -1739,13 +1773,8 @@ fhandler_console::open (int flags, mode_t) setup_io_mutex (); acquire_output_mutex (mutex_timeout); - do - { - pinfo p (con.owner); - if (!p) - con.owner = myself->pid; - } - while (false); + if (!process_alive (con.owner)) + con.owner = GetCurrentProcessId (); /* Open the input handle as handle_ */ bool err = false; @@ -1809,7 +1838,7 @@ fhandler_console::open (int flags, mode_t) set_open_status (); - if (myself->pid == con.owner && wincap.has_con_24bit_colors ()) + if (GetCurrentProcessId () == con.owner && wincap.has_con_24bit_colors ()) { bool is_legacy = false; DWORD dwMode; @@ -1840,26 +1869,88 @@ fhandler_console::open (int flags, mode_t) debug_printf ("opened conin$ %p, conout$ %p", get_handle (), get_output_handle ()); - if (myself->pid == con.owner) + if (GetCurrentProcessId () == con.owner) { if (GetModuleHandle ("ConEmuHk64.dll")) hook_conemu_cygwin_connector (); 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; } +void +fhandler_console::setup_pcon_hand_over () +{ + /* Prepare for pcon hand over */ + if (!inside_pcon_checked) + for (int i = 0; i < NTTYS; i++) + { + if (!cygwin_shared->tty[i]->pcon_activated) + continue; + DWORD owner = cygwin_shared->tty[i]->nat_pipe_owner_pid; + if (get_console_process_id (owner, true, false, false, false)) + { + inside_pcon = true; + atexit (fhandler_console::pcon_hand_over_proc); + parent_pty = i; + break; + } + } + inside_pcon_checked = true; +} + +void +fhandler_console::pcon_hand_over_proc (void) +{ + if (!inside_pcon) + return; + tty *ttyp = cygwin_shared->tty[parent_pty]; + char buf[MAX_PATH]; + shared_name (buf, PIPE_SW_MUTEX, parent_pty); + HANDLE mtx = OpenMutex (MAXIMUM_ALLOWED, FALSE, buf); + WaitForSingleObject (mtx, INFINITE); + ReleaseMutex (mtx); + DWORD res = WaitForSingleObject (mtx, INFINITE); + if (res == WAIT_OBJECT_0 || res == WAIT_ABANDONED) + { + DWORD owner = ttyp->nat_pipe_owner_pid; + if (owner == GetCurrentProcessId () + || owner == (myself->exec_dwProcessId ?: myself->dwProcessId)) + fhandler_pty_slave::close_pseudoconsole (ttyp, 0); + } + else + system_printf("Acquiring pcon_ho_mutex failed."); + /* Do not release the mutex. + Hold onto the mutex until this process completes. */ +} + bool fhandler_console::open_setup (int flags) { set_flags ((flags & ~O_TEXT) | O_BINARY); if (myself->set_ctty (this, flags) && !myself->cygstarted) - init_console_handler (true); + { + init_console_handler (true); + setup_pcon_hand_over (); + + /* Initialize handle_set */ + handle_set.input_handle = get_handle (); + handle_set.output_handle = get_output_handle (); + handle_set.input_mutex = input_mutex; + handle_set.output_mutex = output_mutex; + handle_set.unit = unit; + } return fhandler_base::open_setup (flags); } @@ -1885,16 +1976,16 @@ fhandler_console::close () acquire_output_mutex (mutex_timeout); - if (shared_console_info[unit]) + if (shared_console_info[unit] && !myself->cygstarted + && (dev_t) myself->ctty == get_device ()) { /* Restore console mode if this is the last closure. */ OBJECT_BASIC_INFORMATION obi; NTSTATUS status; status = NtQueryObject (get_handle (), ObjectBasicInformation, &obi, sizeof obi, NULL); - if ((NT_SUCCESS (status) && obi.HandleCount == 1 - && (dev_t) myself->ctty == get_device ()) - || myself->pid == con.owner) + if (NT_SUCCESS (status) + && obi.HandleCount == (con.owner == GetCurrentProcessId () ? 2 : 3)) { /* Cleaning-up console mode for cygwin apps. */ set_output_mode (tty::restore, &get_ttyp ()->ti, &handle_set); @@ -1903,16 +1994,22 @@ fhandler_console::close () } } - if (shared_console_info[unit] && con.owner == myself->pid) + if (shared_console_info[unit] && con.owner == GetCurrentProcessId ()) { if (master_thread_started) { 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 = (DWORD) -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 +2024,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 +2049,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; } @@ -2859,6 +2974,8 @@ fhandler_console::char_command (char c) } if (con.args[i] == 1) /* DECCKM */ con.cursor_key_app_mode = (c == 'h'); + if (con.args[i] == 9001) /* win32-input-mode (https://github.com/microsoft/terminal/blob/main/doc/specs/%234999%20-%20Improved%20keyboard%20handling%20in%20Conpty.md) */ + set_disable_master_thread (c == 'h', this); } /* Call fix_tab_position() if screen has been alternated. */ if (need_fix_tab_position) @@ -3375,7 +3492,7 @@ enum_proc (const LOGFONTW *lf, const TEXTMETRICW *tm, } static void -check_font (HANDLE hdl, pid_t owner) +check_font (HANDLE hdl, DWORD owner) { CONSOLE_FONT_INFOEX cfi; LOGFONTW lf; @@ -4261,6 +4378,7 @@ fhandler_console::fixup_after_fork_exec (bool execing) cygheap->ctty = NULL; return; } + setup_pcon_hand_over (); if (!execing) return; diff --git a/winsup/cygwin/fhandler/disk_file.cc b/winsup/cygwin/fhandler/disk_file.cc index 2cfac6b..794c8eb 100644 --- a/winsup/cygwin/fhandler/disk_file.cc +++ b/winsup/cygwin/fhandler/disk_file.cc @@ -1810,6 +1810,9 @@ fhandler_disk_file::prw_open (bool write, void *aio) return -1; } + /* prw_handle is invalid after fork. */ + need_fork_fixup (true); + /* record prw_handle's asyncness for subsequent pread/pwrite operations */ prw_handle_isasync = !!aio; return 0; diff --git a/winsup/cygwin/fhandler/dsp.cc b/winsup/cygwin/fhandler/dsp.cc index 59c11ac..605a048 100644 --- a/winsup/cygwin/fhandler/dsp.cc +++ b/winsup/cygwin/fhandler/dsp.cc @@ -1026,19 +1026,19 @@ fhandler_dev_dsp::fhandler_dev_dsp (): ssize_t fhandler_dev_dsp::write (const void *ptr, size_t len) { - return base ()->_write (ptr, len); + return base ()->_write (ptr, len, this); } void fhandler_dev_dsp::read (void *ptr, size_t& len) { - base ()->_read (ptr, len); + base ()->_read (ptr, len, this); } int fhandler_dev_dsp::ioctl (unsigned int cmd, void *buf) { - return base ()->_ioctl (cmd, buf); + return base ()->_ioctl (cmd, buf, this); } int @@ -1065,7 +1065,6 @@ fhandler_dev_dsp::open (int flags, mode_t mode) { int ret = -1, err = 0; UINT num_in = 0, num_out = 0; - set_flags ((flags & ~O_TEXT) | O_BINARY); // Work out initial sample format & frequency, /dev/dsp defaults audioformat_ = AFMT_U8; audiofreq_ = 8000; @@ -1105,11 +1104,11 @@ fhandler_dev_dsp::open (int flags, mode_t mode) return ret; } -#define IS_WRITE() ((get_flags() & O_ACCMODE) != O_RDONLY) -#define IS_READ() ((get_flags() & O_ACCMODE) != O_WRONLY) +#define IS_WRITE() ((fh->get_flags() & O_ACCMODE) != O_RDONLY) +#define IS_READ() ((fh->get_flags() & O_ACCMODE) != O_WRONLY) ssize_t -fhandler_dev_dsp::_write (const void *ptr, size_t len) +fhandler_dev_dsp::_write (const void *ptr, size_t len, fhandler_dev_dsp *fh) { debug_printf ("ptr=%p len=%ld", ptr, len); int len_s = len; @@ -1168,7 +1167,7 @@ fhandler_dev_dsp::_write (const void *ptr, size_t len) } void -fhandler_dev_dsp::_read (void *ptr, size_t& len) +fhandler_dev_dsp::_read (void *ptr, size_t& len, fhandler_dev_dsp *fh) { debug_printf ("ptr=%p len=%ld", ptr, len); @@ -1244,7 +1243,7 @@ fhandler_dev_dsp::close () } int -fhandler_dev_dsp::_ioctl (unsigned int cmd, void *buf) +fhandler_dev_dsp::_ioctl (unsigned int cmd, void *buf, fhandler_dev_dsp *fh) { debug_printf ("audio_in=%p audio_out=%p", audio_in_, audio_out_); int *intbuf = (int *) buf; @@ -1349,7 +1348,7 @@ fhandler_dev_dsp::_ioctl (unsigned int cmd, void *buf) CASE (SNDCTL_DSP_STEREO) { int nChannels = *intbuf + 1; - int res = _ioctl (SNDCTL_DSP_CHANNELS, &nChannels); + int res = _ioctl (SNDCTL_DSP_CHANNELS, &nChannels, fh); *intbuf = nChannels - 1; return res; } @@ -1547,3 +1546,10 @@ fhandler_dev_dsp::read_ready () { return base ()->_read_ready (); } + +bool +fhandler_dev_dsp::open_setup (int flags) +{ + set_flags ((flags & ~O_TEXT) | O_BINARY); + return fhandler_base::open_setup (flags); +} diff --git a/winsup/cygwin/fhandler/fifo.cc b/winsup/cygwin/fhandler/fifo.cc index efea508..ee49ce6 100644 --- a/winsup/cygwin/fhandler/fifo.cc +++ b/winsup/cygwin/fhandler/fifo.cc @@ -669,7 +669,7 @@ fhandler_fifo::create_shmem (bool only_open) { HANDLE sect; OBJECT_ATTRIBUTES attr; - NTSTATUS status; + NTSTATUS status = STATUS_SUCCESS; LARGE_INTEGER size = { .QuadPart = sizeof (fifo_shmem_t) }; SIZE_T viewsize = sizeof (fifo_shmem_t); PVOID addr = NULL; diff --git a/winsup/cygwin/fhandler/pipe.cc b/winsup/cygwin/fhandler/pipe.cc index 4c4ad03..6a1ef03 100644 --- a/winsup/cygwin/fhandler/pipe.cc +++ b/winsup/cygwin/fhandler/pipe.cc @@ -13,6 +13,7 @@ details. */ #include "security.h" #include "path.h" #include "fhandler.h" +#include "select.h" #include "dtable.h" #include "cygheap.h" #include "pinfo.h" @@ -53,6 +54,16 @@ fhandler_pipe::set_pipe_non_blocking (bool nonblocking) NTSTATUS status; IO_STATUS_BLOCK io; FILE_PIPE_INFORMATION fpi; + bool was_blocking_read_pipe_new = was_blocking_read_pipe; + + if (get_device () == FH_PIPER && nonblocking && !was_blocking_read_pipe) + { + status = NtQueryInformationFile (get_handle (), &io, &fpi, sizeof fpi, + FilePipeInformation); + if (NT_SUCCESS (status)) + was_blocking_read_pipe_new = + (fpi.CompletionMode == FILE_PIPE_QUEUE_OPERATION); + } fpi.ReadMode = FILE_PIPE_BYTE_STREAM_MODE; fpi.CompletionMode = nonblocking ? FILE_PIPE_COMPLETE_OPERATION @@ -61,6 +72,11 @@ fhandler_pipe::set_pipe_non_blocking (bool nonblocking) FilePipeInformation); if (!NT_SUCCESS (status)) debug_printf ("NtSetInformationFile(FilePipeInformation): %y", status); + else + { + was_blocking_read_pipe = was_blocking_read_pipe_new; + is_blocking_read_pipe = !nonblocking; + } } int @@ -94,6 +110,8 @@ fhandler_pipe::init (HANDLE f, DWORD a, mode_t mode, int64_t uniq_id) even with FILE_SYNCHRONOUS_IO_NONALERT. */ set_pipe_non_blocking (get_device () == FH_PIPER ? true : is_nonblocking ()); + was_blocking_read_pipe = false; + return 1; } @@ -288,6 +306,9 @@ fhandler_pipe::raw_read (void *ptr, size_t& len) if (!len) return; + if (is_blocking_read_pipe) + set_pipe_non_blocking (true); + DWORD timeout = is_nonblocking () ? 0 : INFINITE; DWORD waitret = cygwait (read_mtx, timeout); switch (waitret) @@ -418,6 +439,7 @@ fhandler_pipe_fifo::raw_write (const void *ptr, size_t len) NTSTATUS status = STATUS_SUCCESS; IO_STATUS_BLOCK io; HANDLE evt; + bool short_write_once = false; if (!len) return 0; @@ -456,6 +478,7 @@ fhandler_pipe_fifo::raw_write (const void *ptr, size_t len) len1 = chunk; else len1 = (ULONG) left; + /* NtWriteFile returns success with # of bytes written == 0 if writing on a non-blocking pipe fails because the pipe buffer doesn't have sufficient space. @@ -483,9 +506,16 @@ fhandler_pipe_fifo::raw_write (const void *ptr, size_t len) (PVOID) ptr, len1, NULL, NULL); if (status == STATUS_PENDING) { - while (WAIT_TIMEOUT == - (waitret = cygwait (evt, (DWORD) 0, cw_cancel | cw_sig))) + do { + /* To allow constant reader_closed() checking even if the + signal has been set up with SA_RESTART, we're handling + the signal here --> cw_sig_eintr. */ + waitret = cygwait (evt, (DWORD) 0, cw_cancel | cw_sig_eintr); + /* Break out if no SA_RESTART. */ + if (waitret == WAIT_SIGNALED + && !_my_tls.call_signal_handler ()) + break; if (reader_closed ()) { CancelIo (get_handle ()); @@ -493,9 +523,20 @@ fhandler_pipe_fifo::raw_write (const void *ptr, size_t len) raise (SIGPIPE); goto out; } - else - cygwait (select_sem, 10); + /* Break out on completion */ + if (waitret == WAIT_OBJECT_0) + break; + /* If we got a timeout in the blocking case, and we already + did a short write, we got a signal in the previous loop. */ + if (waitret == WAIT_TIMEOUT && short_write_once) + { + waitret = WAIT_SIGNALED; + break; + } + cygwait (select_sem, 10, cw_cancel); } + /* Loop in case of blocking write or SA_RESTART */ + while (waitret == WAIT_TIMEOUT || waitret == WAIT_SIGNALED); /* If io.Status is STATUS_CANCELLED after CancelIo, IO has actually been cancelled and io.Information contains the number of bytes processed so far. @@ -509,13 +550,38 @@ fhandler_pipe_fifo::raw_write (const void *ptr, size_t len) status = STATUS_THREAD_CANCELED; else if (waitret == WAIT_SIGNALED) status = STATUS_THREAD_SIGNALED; + else if (waitret == WAIT_TIMEOUT && io.Status == STATUS_CANCELLED) + status = STATUS_SUCCESS; else status = io.Status; } - if (!is_nonblocking () || !NT_SUCCESS (status) || io.Information > 0 - || len <= PIPE_BUF) + if (status != STATUS_THREAD_SIGNALED && !NT_SUCCESS (status)) + break; + if (io.Information > 0 || len <= PIPE_BUF || short_write_once) break; - len1 >>= 1; + /* Independent of being blocking or non-blocking, if we're here, + the pipe has less space than requested. If the pipe is a + non-Cygwin pipe, just try the old strategy of trying a half + write. If the pipe has at + least PIPE_BUF bytes available, try to write all matching + PIPE_BUF sized blocks. If it's less than PIPE_BUF, try + the next less power of 2 bytes. This is not really the Linux + strategy because Linux is filling the pages of a pipe buffer + in a very implementation-defined way we can't emulate, but it + resembles it closely enough to get useful results. */ + ssize_t avail = pipe_data_available (-1, this, get_handle (), + PDA_WRITE); + if (avail < 1) /* error or pipe closed */ + break; + if (avail > len1) /* somebody read from the pipe */ + avail = len1; + if (avail == 1) /* 1 byte left or non-Cygwin pipe */ + len1 >>= 1; + else if (avail >= PIPE_BUF) + len1 = avail & ~(PIPE_BUF - 1); + else + len1 = 1 << (63 - __builtin_clzl (avail)); + short_write_once = true; } if (isclosed ()) /* A signal handler might have closed the fd. */ { @@ -545,7 +611,7 @@ fhandler_pipe_fifo::raw_write (const void *ptr, size_t len) else __seterrno_from_nt_status (status); - if (nbytes_now == 0) + if (nbytes_now == 0 || short_write_once) break; } out: @@ -675,6 +741,8 @@ fhandler_pipe::close () CloseHandle (query_hdl); if (query_hdl_close_req_evt) CloseHandle (query_hdl_close_req_evt); + if (was_blocking_read_pipe) + set_pipe_non_blocking (false); int ret = fhandler_base::close (); ReleaseMutex (hdl_cnt_mtx); CloseHandle (hdl_cnt_mtx); @@ -1327,6 +1395,7 @@ fhandler_pipe::spawn_worker (int fileno_stdin, int fileno_stdout, { fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd; pipe->set_pipe_non_blocking (false); + need_send_noncygchld_sig = true; } /* If multiple writers including non-cygwin app exist, the non-cygwin @@ -1352,3 +1421,21 @@ fhandler_pipe::spawn_worker (int fileno_stdin, int fileno_stdout, t->kill_pgrp (__SIGNONCYGCHLD); } } + +void +fhandler_pipe::sigproc_worker (void) +{ + cygheap_fdenum cfd (false); + while (cfd.next () >= 0) + if (cfd->get_dev () == FH_PIPEW) + { + fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd; + if (pipe->need_close_query_hdl ()) + pipe->close_query_handle (); + } + else if (cfd->get_dev () == FH_PIPER) + { + fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd; + pipe->is_blocking_read_pipe = true; + } +} diff --git a/winsup/cygwin/fhandler/proc.cc b/winsup/cygwin/fhandler/proc.cc index be107cb..fcd6441 100644 --- a/winsup/cygwin/fhandler/proc.cc +++ b/winsup/cygwin/fhandler/proc.cc @@ -2153,8 +2153,7 @@ format_proc_locale_proc (LPWSTR win_locale, DWORD info, LPARAM param) if (!(cp2 = wcschr (cp + 2, L'-'))) return TRUE; /* Otherwise, store in iso15924 */ - if (iso15924) - wcpcpy (wcpncpy (iso15924, cp, cp2 - cp), L";"); + wcpcpy (wcpncpy (iso15924, cp, cp2 - cp), L";"); } cp = wcsrchr (win_locale, L'-'); if (cp) diff --git a/winsup/cygwin/fhandler/pty.cc b/winsup/cygwin/fhandler/pty.cc index 9d7ef3c..4f0f718 100644 --- a/winsup/cygwin/fhandler/pty.cc +++ b/winsup/cygwin/fhandler/pty.cc @@ -74,58 +74,6 @@ void release_attach_mutex (void) ReleaseMutex (attach_mutex); } -inline static bool process_alive (DWORD pid); - -/* This functions looks for a process which attached to the same console - with current process and is matched to given conditions: - match: If true, return given pid if the process pid attaches to the - same console, otherwise, return 0. If false, return pid except - for given pid. - cygwin: return only process's pid which has cygwin pid. - stub_only: return only stub process's pid of non-cygwin process. */ -DWORD -fhandler_pty_common::get_console_process_id (DWORD pid, bool match, - bool cygwin, bool stub_only, - bool nat) -{ - tmp_pathbuf tp; - DWORD *list = (DWORD *) tp.c_get (); - const DWORD buf_size = NT_MAX_PATH / sizeof (DWORD); - - DWORD num = GetConsoleProcessList (list, buf_size); - if (num == 0 || num > buf_size) - return 0; - - DWORD res_pri = 0, res = 0; - /* Last one is the oldest. */ - /* https://github.com/microsoft/terminal/issues/95 */ - for (int i = (int) num - 1; i >= 0; i--) - if ((match && list[i] == pid) || (!match && list[i] != pid)) - { - if (!cygwin) - { - res_pri = list[i]; - break; - } - else - { - pinfo p (cygwin_pid (list[i])); - if (nat && !!p && !ISSTATE(p, PID_NOTCYGWIN)) - continue; - if (!!p && p->exec_dwProcessId) - { - res_pri = stub_only ? p->exec_dwProcessId : list[i]; - break; - } - if (!p && !res && process_alive (list[i]) && stub_only) - res = list[i]; - if (!!p && !res && !stub_only) - res = list[i]; - } - } - return res_pri ?: res; -} - static bool isHybrid; /* Set true if the active pipe is set to nat pipe owned by myself even though the current process is a cygwin process. */ @@ -1113,27 +1061,10 @@ fhandler_pty_slave::set_switch_to_nat_pipe (void) } inline static bool -process_alive (DWORD pid) -{ - /* This function is very similar to _pinfo::alive(), however, this - can be used for non-cygwin process which is started from non-cygwin - shell. In addition, this checks exit code as well. */ - if (pid == 0) - return false; - HANDLE h = OpenProcess (PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); - if (h == NULL) - return false; - DWORD exit_code; - BOOL r = GetExitCodeProcess (h, &exit_code); - CloseHandle (h); - if (r && exit_code == STILL_ACTIVE) - return true; - return false; -} - -inline static bool nat_pipe_owner_self (DWORD pid) { + if (pid == GetCurrentProcessId ()) + return true; return (pid == (myself->exec_dwProcessId ?: myself->dwProcessId)); } @@ -3118,8 +3049,22 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, return res; /* Discard write data */ while (towrite) { + ssize_t space = towrite; if (!is_echo) { + IO_STATUS_BLOCK iosb = {{0}, 0}; + FILE_PIPE_LOCAL_INFORMATION fpli = {0}; + NTSTATUS status; + + status = NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli), + FilePipeLocalInformation); + if (!NT_SUCCESS (status)) + { + if (towrite < len) + break; + len = -1; + return FALSE; + } if (ttyp->output_stopped && is_nonblocking) { if (towrite < len) @@ -3131,13 +3076,18 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, return TRUE; } } - while (ttyp->output_stopped) - cygwait (10); + if (ttyp->output_stopped || fpli.WriteQuotaAvailable == 0) + { + cygwait (1); + continue; + } + space = fpli.WriteQuotaAvailable; } if (!(ttyp->ti.c_oflag & OPOST)) // raw output mode { DWORD n = MIN (OUT_BUFFER_SIZE, towrite); + n = MIN (n, space); res = WriteFile (h, ptr, n, &n, NULL); if (!res) break; @@ -3150,7 +3100,7 @@ fhandler_pty_common::process_opost_output (HANDLE h, const void *ptr, char *buf = (char *)ptr; DWORD n = 0; ssize_t rc = 0; - while (n < OUT_BUFFER_SIZE && rc < towrite) + while (n < OUT_BUFFER_SIZE && n < space && rc < towrite) { switch (buf[rc]) { @@ -3522,11 +3472,16 @@ fhandler_pty_slave::get_winpid_to_hand_over (tty *ttyp, { /* Search another native process which attaches to the same console */ DWORD current_pid = myself->exec_dwProcessId ?: myself->dwProcessId; + if (ttyp->nat_pipe_owner_pid == GetCurrentProcessId ()) + current_pid = GetCurrentProcessId (); switch_to = get_console_process_id (current_pid, false, true, true, true); if (!switch_to) switch_to = get_console_process_id (current_pid, false, true, false, true); + if (!switch_to) + switch_to = get_console_process_id (current_pid, + false, false, false, false); } return switch_to; } @@ -3554,13 +3509,13 @@ fhandler_pty_slave::hand_over_only (tty *ttyp, DWORD force_switch_to) void fhandler_pty_slave::close_pseudoconsole (tty *ttyp, DWORD force_switch_to) { - DWORD switch_to = get_winpid_to_hand_over (ttyp, force_switch_to); acquire_attach_mutex (mutex_timeout); ttyp->previous_code_page = GetConsoleCP (); ttyp->previous_output_code_page = GetConsoleOutputCP (); release_attach_mutex (); if (nat_pipe_owner_self (ttyp->nat_pipe_owner_pid)) { /* I am owner of the nat pipe. */ + DWORD switch_to = get_winpid_to_hand_over (ttyp, force_switch_to); if (switch_to) { /* Change pseudo console owner to another process (switch_to). */ diff --git a/winsup/cygwin/fhandler/socket.cc b/winsup/cygwin/fhandler/socket.cc index f7c5ff6..c0cef7d 100644 --- a/winsup/cygwin/fhandler/socket.cc +++ b/winsup/cygwin/fhandler/socket.cc @@ -86,7 +86,7 @@ struct __old_ifreq { int fhandler_socket::ioctl (unsigned int cmd, void *p) { - extern int get_ifconf (struct ifconf *ifc, int what); /* net.cc */ + extern int get_ifconf (struct ifconf *ifc, unsigned int what); /* net.cc */ int res; struct ifconf ifc, *ifcp; struct ifreq *ifrp; diff --git a/winsup/cygwin/fhandler/tape.cc b/winsup/cygwin/fhandler/tape.cc index 0e235f1..732fd1b 100644 --- a/winsup/cygwin/fhandler/tape.cc +++ b/winsup/cygwin/fhandler/tape.cc @@ -894,9 +894,9 @@ mtinfo_drive::get_status (HANDLE mt, struct mtget *get) } int -mtinfo_drive::set_options (HANDLE mt, int32_t options) +mtinfo_drive::set_options (HANDLE mt, uint32_t options) { - int32_t what = (options & MT_ST_OPTIONS); + uint32_t what = (options & MT_ST_OPTIONS); bool call_setparams = false; bool set; TAPE_SET_DRIVE_PARAMETERS sdp = diff --git a/winsup/cygwin/fhandler/termios.cc b/winsup/cygwin/fhandler/termios.cc index d106955..585e6ac 100644 --- a/winsup/cygwin/fhandler/termios.cc +++ b/winsup/cygwin/fhandler/termios.cc @@ -20,6 +20,7 @@ details. */ #include "cygheap.h" #include "child_info.h" #include "ntdll.h" +#include "tls_pbuf.h" /* Wait time for some treminal mutexes. This is set to 0 when the process calls CreateProcess() with DEBUG_PROCESS flag, because @@ -827,3 +828,80 @@ fhandler_termios::spawn_worker::close_handle_set () if (cons_need_cleanup) fhandler_console::close_handle_set (&cons_handle_set); } + +void +fhandler_termios::atexit_func () +{ + fhandler_console::pcon_hand_over_proc (); +} + +bool +fhandler_termios::process_alive (DWORD pid) +{ + /* This function is very similar to _pinfo::alive(), however, this + can be used for non-cygwin process which is started from non-cygwin + shell. In addition, this checks exit code as well. */ + if (pid == 0) + return false; + HANDLE h = OpenProcess (PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid); + if (h == NULL) + return false; + DWORD exit_code; + BOOL r = GetExitCodeProcess (h, &exit_code); + CloseHandle (h); + if (r && exit_code == STILL_ACTIVE) + return true; + return false; +} + +/* This functions looks for a process which attached to the same console + with current process and is matched to given conditions: + match: If true, return given pid if the process pid attaches to the + same console, otherwise, return 0. If false, return pid except + for given pid. + cygwin: return only process's pid which has cygwin pid. + stub_only: return only stub process's pid of non-cygwin process. */ +DWORD +fhandler_termios::get_console_process_id (DWORD pid, bool match, + bool cygwin, bool stub_only, + bool nat) +{ + tmp_pathbuf tp; + DWORD *list = (DWORD *) tp.c_get (); + const DWORD buf_size = NT_MAX_PATH / sizeof (DWORD); + + DWORD num = GetConsoleProcessList (list, buf_size); + if (num == 0 || num > buf_size) + return 0; + + DWORD res_pri = 0, res = 0; + /* Last one is the oldest. */ + /* https://github.com/microsoft/terminal/issues/95 */ + for (int i = (int) num - 1; i >= 0; i--) + if ((match && list[i] == pid) || (!match && list[i] != pid)) + { + if (!process_alive (list[i])) + continue; + if (!cygwin) + { + res_pri = list[i]; + break; + } + else + { + pinfo p (cygwin_pid (list[i])); + if (nat && !!p && !ISSTATE(p, PID_NOTCYGWIN)) + continue; + if (!!p && p->exec_dwProcessId) + { + res_pri = stub_only ? p->exec_dwProcessId : list[i]; + break; + } + if (!p && !res && stub_only) + res = list[i]; + if (!!p && !res && !stub_only) + res = list[i]; + } + } + return res_pri ?: res; +} diff --git a/winsup/cygwin/flock.cc b/winsup/cygwin/flock.cc index 0f1efa0..3821bdd 100644 --- a/winsup/cygwin/flock.cc +++ b/winsup/cygwin/flock.cc @@ -297,6 +297,7 @@ class inode_t HANDLE i_dir; HANDLE i_mtx; uint32_t i_cnt; /* # of threads referencing this instance. */ + uint32_t i_lock_cnt; /* # of locks for this file */ public: inode_t (dev_t dev, ino_t ino); @@ -321,6 +322,8 @@ class inode_t void unlock_and_remove_if_unused (); lockf_t *get_all_locks_list (); + uint32_t get_lock_count () /* needs get_all_locks_list() */ + { return i_lock_cnt; } bool del_my_locks (long long id, HANDLE fhdl); }; @@ -503,7 +506,8 @@ inode_t::get (dev_t dev, ino_t ino, bool create_if_missing, bool lock) } inode_t::inode_t (dev_t dev, ino_t ino) -: i_lockf (NULL), i_all_lf (NULL), i_dev (dev), i_ino (ino), i_cnt (0L) +: i_lockf (NULL), i_all_lf (NULL), i_dev (dev), i_ino (ino), i_cnt (0L), + i_lock_cnt (0) { HANDLE parent_dir; WCHAR name[48]; @@ -610,17 +614,16 @@ inode_t::get_all_locks_list () dbi->ObjectName.Buffer[LOCK_OBJ_NAME_LEN] = L'\0'; if (!newlock.from_obj_name (this, &i_all_lf, dbi->ObjectName.Buffer)) continue; - if (lock - i_all_lf >= MAX_LOCKF_CNT) - { - system_printf ("Warning, can't handle more than %d locks per file.", - MAX_LOCKF_CNT); - break; - } + /* This should not be happen. The number of locks is limitted + in lf_setlock() and lf_clearlock() so that it does not + exceed MAX_LOCKF_CNT. */ + assert (lock - i_all_lf < MAX_LOCKF_CNT); if (lock > i_all_lf) lock[-1].lf_next = lock; new (lock++) lockf_t (newlock); } } + i_lock_cnt = lock - i_all_lf; /* If no lock has been found, return NULL. */ if (lock == i_all_lf) return NULL; @@ -1190,6 +1193,12 @@ restart: /* Entry point after a restartable signal came in. */ return -1; } +/* The total number of locks shall not exceed MAX_LOCKF_CNT. + If once it exceeds, lf_fildoverlap() cannot work correctly. + Therefore, lf_setlock() and lf_clearlock() control the + total number of locks not to exceed MAX_LOCKF_CNT. When + they detect that the operation will cause excess, they + return ENOCLK. */ /* * Set a byte-range lock. */ @@ -1346,14 +1355,31 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl) * * Handle any locks that overlap. */ + node->get_all_locks_list (); /* Update lock count */ + uint32_t lock_cnt = node->get_lock_count (); + /* lf_clearlock() sometimes increases the number of locks. Without + this room, the unlocking will never succeed in some situation. */ + const uint32_t room_for_clearlock = 2; + const int incr[] = {1, 1, 2, 2, 3, 2}; + int decr = 0; + prev = head; block = *head; needtolink = 1; for (;;) { ovcase = lf_findoverlap (block, lock, SELF, &prev, &overlap); + /* Estimate the maximum increase in number of the locks that + can occur here. If this possibly exceeds the MAX_LOCKF_CNT, + return ENOLCK. */ if (ovcase) - block = overlap->lf_next; + { + block = overlap->lf_next; + HANDLE ov_obj = overlap->lf_obj; + decr = (ov_obj && get_obj_handle_count (ov_obj) == 1) ? 1 : 0; + } + if (needtolink) + lock_cnt += incr[ovcase] - decr; /* * Six cases: * 0) no overlap @@ -1368,6 +1394,8 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl) case 0: /* no overlap */ if (needtolink) { + if (lock_cnt > MAX_LOCKF_CNT - room_for_clearlock) + return ENOLCK; *prev = lock; lock->lf_next = overlap; lock->create_lock_obj (); @@ -1380,6 +1408,8 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl) * able to acquire it. * Cygwin: Always wake lock. */ + if (lock_cnt > MAX_LOCKF_CNT - room_for_clearlock) + return ENOLCK; lf_wakelock (overlap, fhdl); overlap->lf_type = lock->lf_type; overlap->create_lock_obj (); @@ -1397,6 +1427,11 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl) *clean = lock; break; } + if (overlap->lf_start < lock->lf_start + && overlap->lf_end > lock->lf_end) + lock_cnt++; + if (lock_cnt > MAX_LOCKF_CNT - room_for_clearlock) + return ENOLCK; if (overlap->lf_start == lock->lf_start) { *prev = lock; @@ -1413,6 +1448,8 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl) break; case 3: /* lock contains overlap */ + if (needtolink && lock_cnt > MAX_LOCKF_CNT - room_for_clearlock) + return ENOLCK; /* * If downgrading lock, others may be able to * acquire it, otherwise take the list. @@ -1440,6 +1477,8 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl) /* * Add lock after overlap on the list. */ + if (lock_cnt > MAX_LOCKF_CNT - room_for_clearlock) + return ENOLCK; lock->lf_next = overlap->lf_next; overlap->lf_next = lock; overlap->lf_end = lock->lf_start - 1; @@ -1454,13 +1493,16 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl) /* * Add the new lock before overlap. */ - if (needtolink) { + if (needtolink) + { + if (lock_cnt > MAX_LOCKF_CNT - room_for_clearlock) + return ENOLCK; *prev = lock; lock->lf_next = overlap; - } + lock->create_lock_obj (); + } overlap->lf_start = lock->lf_end + 1; lf_wakelock (overlap, fhdl); - lock->create_lock_obj (); overlap->create_lock_obj (); break; } @@ -1482,12 +1524,35 @@ lf_clearlock (lockf_t *unlock, lockf_t **clean, HANDLE fhdl) lockf_t *lf = *head; lockf_t *overlap, **prev; int ovcase; + inode_t *node = lf->lf_inode; + tmp_pathbuf tp; + node->i_all_lf = (lockf_t *) tp.w_get (); + node->get_all_locks_list (); /* Update lock count */ + uint32_t lock_cnt = node->get_lock_count (); + bool first_loop = true; if (lf == NOLOCKF) return 0; prev = head; while ((ovcase = lf_findoverlap (lf, unlock, SELF, &prev, &overlap))) { + /* Estimate the maximum increase in number of the locks that + can occur here. If this possibly exceeds the MAX_LOCKF_CNT, + return ENOLCK. */ + HANDLE ov_obj = overlap->lf_obj; + if (first_loop) + { + const int incr[] = {0, 0, 1, 1, 2, 1}; + int decr = (ov_obj && get_obj_handle_count (ov_obj) == 1) ? 1 : 0; + lock_cnt += incr[ovcase] - decr; + if (ovcase == 2 + && overlap->lf_start < unlock->lf_start + && overlap->lf_end > unlock->lf_end) + lock_cnt++; + if (lock_cnt > MAX_LOCKF_CNT) + return ENOLCK; + } + /* * Wakeup the list of locks to be retried. */ @@ -1520,6 +1585,7 @@ lf_clearlock (lockf_t *unlock, lockf_t **clean, HANDLE fhdl) lf = overlap->lf_next; overlap->lf_next = *clean; *clean = overlap; + first_loop = false; continue; case 4: /* overlap starts before lock */ @@ -1527,6 +1593,7 @@ lf_clearlock (lockf_t *unlock, lockf_t **clean, HANDLE fhdl) prev = &overlap->lf_next; lf = overlap->lf_next; overlap->create_lock_obj (); + first_loop = false; continue; case 5: /* overlap ends after lock */ diff --git a/winsup/cygwin/include/asm/socket.h b/winsup/cygwin/include/asm/socket.h index 9aeb889..276df3a 100644 --- a/winsup/cygwin/include/asm/socket.h +++ b/winsup/cygwin/include/asm/socket.h @@ -17,8 +17,8 @@ details. */ #define IOC_IN 0x80000000 /* copy in parameters */ #define _IO(x,y) (IOC_VOID|(x<<8)|y) -#define _IOR(x,y,t) (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y) -#define _IOW(x,y,t) (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y) +#define _IOR(x,y,t) (IOC_OUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y) +#define _IOW(x,y,t) (IOC_IN|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y) #define SIOCATMARK _IOR('s', 7, long) /* at oob mark? */ #define FIONREAD _IOR('f', 127, long) /* get # bytes to read */ diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index 0f87fbc..fb821a6 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -11,7 +11,7 @@ details. */ changes to the DLL and is mainly informative in nature. */ #define CYGWIN_VERSION_DLL_MAJOR 3005 -#define CYGWIN_VERSION_DLL_MINOR 4 +#define CYGWIN_VERSION_DLL_MINOR 5 /* CYGWIN_VERSION_DLL_COMBINED gives us a single number representing the combined DLL major and minor numbers. */ diff --git a/winsup/cygwin/include/getopt.h b/winsup/cygwin/include/getopt.h index c5af1ac..63e068b 100644 --- a/winsup/cygwin/include/getopt.h +++ b/winsup/cygwin/include/getopt.h @@ -85,4 +85,4 @@ int getopt_long_only (int, char *const *, const char *, const struct option *, i #endif /* __GETOPT_LONG_H__ */ #endif /* __UNISTD_GETOPT__ */ -#endif /*_INSIDE_NEWLIB*/ +#endif /*_LIBC */ diff --git a/winsup/cygwin/include/pthread.h b/winsup/cygwin/include/pthread.h index 66d367d..8e29630 100644 --- a/winsup/cygwin/include/pthread.h +++ b/winsup/cygwin/include/pthread.h @@ -110,10 +110,13 @@ typedef struct _pthread_cleanup_handler void _pthread_cleanup_push (__pthread_cleanup_handler *handler); void _pthread_cleanup_pop (int execute); -#define pthread_cleanup_push(_fn, _arg) { __pthread_cleanup_handler __cleanup_handler = \ - { _fn, _arg, NULL }; \ - _pthread_cleanup_push( &__cleanup_handler ); -#define pthread_cleanup_pop(_execute) _pthread_cleanup_pop( _execute ); } +#define pthread_cleanup_push(_fn, _arg) \ + do { \ + __pthread_cleanup_handler __cleanup_handler = { _fn, _arg, NULL }; \ + _pthread_cleanup_push(&__cleanup_handler) +#define pthread_cleanup_pop(_execute) \ + _pthread_cleanup_pop(_execute); \ + } while (0) /* Condition variables */ int pthread_cond_broadcast (pthread_cond_t *); @@ -244,7 +247,7 @@ int pthread_getattr_np (pthread_t, pthread_attr_t *); int pthread_getname_np (pthread_t, char *, size_t) __attribute__((__nonnull__(2))); int pthread_setaffinity_np (pthread_t, size_t, const cpu_set_t *); int pthread_setname_np (pthread_t, const char *) __attribute__((__nonnull__(2))); -int pthread_sigqueue (pthread_t *, int, const union sigval); +int pthread_sigqueue (pthread_t, int, const union sigval); int pthread_timedjoin_np (pthread_t, void **, const struct timespec *); int pthread_tryjoin_np (pthread_t, void **); #endif diff --git a/winsup/cygwin/local_includes/fhandler.h b/winsup/cygwin/local_includes/fhandler.h index 87adca9..88a6b7d 100644 --- a/winsup/cygwin/local_includes/fhandler.h +++ b/winsup/cygwin/local_includes/fhandler.h @@ -1197,6 +1197,8 @@ class fhandler_pipe: public fhandler_pipe_fifo private: HANDLE read_mtx; pid_t popen_pid; + bool was_blocking_read_pipe; + bool is_blocking_read_pipe; HANDLE query_hdl; HANDLE hdl_cnt_mtx; HANDLE query_hdl_proc; @@ -1287,6 +1289,7 @@ public: } static void spawn_worker (int fileno_stdin, int fileno_stdout, int fileno_stderr); + static void sigproc_worker (void); }; #define CYGWIN_FIFO_PIPE_NAME_LEN 47 @@ -1967,6 +1970,11 @@ class fhandler_termios: public fhandler_base done_with_debugger /* The key was processed (CTRL_C_EVENT was sent) for inferior of GDB. */ }; + static bool process_alive (DWORD pid); + static DWORD get_console_process_id (DWORD pid, bool match, + bool cygwin = false, + bool stub_only = false, + bool nat = false); public: virtual pid_t tc_getpgid () { return 0; }; @@ -2019,6 +2027,7 @@ class fhandler_termios: public fhandler_base virtual void setpgid_aux (pid_t pid) {} virtual bool need_console_handler () { return false; } virtual bool need_send_ctrl_c_event () { return true; } + static void atexit_func (); struct ptys_handle_set_t { @@ -2089,7 +2098,7 @@ enum cltype class dev_console { - pid_t owner; + DWORD owner; bool is_legacy; bool orig_virtual_terminal_processing_mode; @@ -2160,6 +2169,8 @@ class dev_console char *cons_rapoi; bool cursor_key_app_mode; bool disable_master_thread; + tty::cons_mode curr_input_mode; + tty::cons_mode curr_output_mode; bool master_thread_suspended; int num_processed; /* Number of input events in the current input buffer already processed by cons_master_thread(). */ @@ -2180,10 +2191,6 @@ class dev_console friend class fhandler_console; }; -#define MAX_CONS_DEV (sizeof (unsigned long) * 8) -#define CONS_SCAN_UNUSED (-1) -#define CONS_LIST_USED (-2) - /* This is a input and output console handle */ class fhandler_console: public fhandler_termios { @@ -2241,7 +2248,7 @@ private: void set_cursor_maybe (); static bool create_invisible_console_workaround (bool force); static console_state *open_shared_console (HWND, HANDLE&, bool&); - static void fix_tab_position (HANDLE h, pid_t owner); + static void fix_tab_position (HANDLE h, DWORD owner); /* console mode calls */ const handle_set_t *get_handle_set (void) {return &handle_set;} @@ -2366,9 +2373,9 @@ private: static void set_console_mode_to_native (); bool need_console_handler (); static void set_disable_master_thread (bool x, fhandler_console *cons = NULL); - static DWORD attach_console (pid_t, bool *err = NULL); - static void detach_console (DWORD, pid_t); - pid_t get_owner (); + static DWORD attach_console (DWORD, bool *err = NULL); + static void detach_console (DWORD, DWORD); + DWORD get_owner (); void wpbuf_put (char c); void wpbuf_send (); int fstat (struct stat *buf); @@ -2376,15 +2383,15 @@ private: class console_unit { int n; - unsigned long bitmask; - console_state *shared_console_info; public: - operator console_state * () const {return shared_console_info;} - operator unsigned long () const {return n == CONS_LIST_USED ? bitmask : n;} - console_unit (int); - friend BOOL CALLBACK fhandler_console::enum_windows (HWND, LPARAM); + operator console_state * () const; + operator int () const { return n; } + console_unit (int, HANDLE *input_mutex = NULL); }; + void setup_pcon_hand_over (); + static void pcon_hand_over_proc (); + friend tty_min * tty_list::get_cttyp (); }; @@ -2432,10 +2439,6 @@ class fhandler_pty_common: public fhandler_termios } void resize_pseudo_console (struct winsize *); - static DWORD get_console_process_id (DWORD pid, bool match, - bool cygwin = false, - bool stub_only = false, - bool nat = false); bool to_be_read_from_nat_pipe (void); static DWORD attach_console_temporarily (DWORD target_pid); static void resume_from_temporarily_attach (DWORD resume_pid); @@ -2870,11 +2873,12 @@ class fhandler_dev_dsp: public fhandler_base int close (); void fixup_after_fork (HANDLE); void fixup_after_exec (); + bool open_setup (int); private: - ssize_t _write (const void *, size_t); - void _read (void *, size_t&); - int _ioctl (unsigned int, void *); + ssize_t _write (const void *, size_t, fhandler_dev_dsp *); + void _read (void *, size_t&, fhandler_dev_dsp *); + int _ioctl (unsigned int, void *, fhandler_dev_dsp *); int _fcntl (int cmd, intptr_t); void _fixup_after_fork (HANDLE); void _fixup_after_exec (); diff --git a/winsup/cygwin/local_includes/mtinfo.h b/winsup/cygwin/local_includes/mtinfo.h index 03aabbf..46f8b1b 100644 --- a/winsup/cygwin/local_includes/mtinfo.h +++ b/winsup/cygwin/local_includes/mtinfo.h @@ -101,7 +101,7 @@ class mtinfo_drive int set_compression (HANDLE mt, int32_t count); int set_blocksize (HANDLE mt, DWORD count); int get_status (HANDLE mt, struct mtget *get); - int set_options (HANDLE mt, int32_t options); + int set_options (HANDLE mt, uint32_t options); int async_wait (HANDLE mt, DWORD *bytes_written); public: diff --git a/winsup/cygwin/local_includes/ntdll.h b/winsup/cygwin/local_includes/ntdll.h index 7737ae5..4497fe5 100644 --- a/winsup/cygwin/local_includes/ntdll.h +++ b/winsup/cygwin/local_includes/ntdll.h @@ -23,7 +23,7 @@ extern GUID __cygwin_socket_guid; /* Custom Cygwin-only status codes. */ #define STATUS_THREAD_SIGNALED ((NTSTATUS)0xe0000001) #define STATUS_THREAD_CANCELED ((NTSTATUS)0xe0000002) -#define STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION ((DWORD) 0xe0000269) +#define STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION ((NTSTATUS) 0xe0000269) /* Simplify checking for a transactional error code. */ #define NT_TRANSACTIONAL_ERROR(s) \ diff --git a/winsup/cygwin/local_includes/select.h b/winsup/cygwin/local_includes/select.h index 4e20212..dea0233 100644 --- a/winsup/cygwin/local_includes/select.h +++ b/winsup/cygwin/local_includes/select.h @@ -139,4 +139,9 @@ public: extern "C" int cygwin_select (int , fd_set *, fd_set *, fd_set *, struct timeval *to); +ssize_t pipe_data_available (int, fhandler_base *, HANDLE, int); + +#define PDA_WRITE 0x01 +#define PDA_SELECT 0x02 + #endif /* _SELECT_H_ */ diff --git a/winsup/cygwin/local_includes/shared_info.h b/winsup/cygwin/local_includes/shared_info.h index cbe55a2..4316717 100644 --- a/winsup/cygwin/local_includes/shared_info.h +++ b/winsup/cygwin/local_includes/shared_info.h @@ -33,7 +33,7 @@ public: /* Data accessible to all tasks */ -#define CURR_SHARED_MAGIC 0x9f33cc5dU +#define CURR_SHARED_MAGIC 0x205f4579U #define USER_VERSION 1 @@ -46,6 +46,7 @@ class shared_info DWORD cb; public: tty_list tty; + HWND cons_hwnd[MAX_CONS_DEV]; LONG last_used_bindresvport; DWORD obcaseinsensitive; mtinfo mt; diff --git a/winsup/cygwin/local_includes/tty.h b/winsup/cygwin/local_includes/tty.h index df3bf60..2a047d7 100644 --- a/winsup/cygwin/local_includes/tty.h +++ b/winsup/cygwin/local_includes/tty.h @@ -178,6 +178,7 @@ public: friend class fhandler_pty_master; friend class fhandler_pty_slave; friend class tty_min; + friend class fhandler_console; }; class tty_list @@ -211,4 +212,9 @@ public: }; extern "C" int ttyslot (void); + +/* Console stuff */ +#define MAX_CONS_DEV 128 +#define CONS_SCAN_UNUSED (-1) + #endif /*_TTY_H*/ diff --git a/winsup/cygwin/local_includes/winlean.h b/winsup/cygwin/local_includes/winlean.h index 5bf1be2..62b651b 100644 --- a/winsup/cygwin/local_includes/winlean.h +++ b/winsup/cygwin/local_includes/winlean.h @@ -53,7 +53,10 @@ details. */ #define __undef_CRITICAL #endif +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Warray-bounds" #include <windows.h> +#pragma GCC diagnostic pop #include <wincrypt.h> #include <lmcons.h> #include <ntdef.h> diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc index 08c584f..737e494 100644 --- a/winsup/cygwin/net.cc +++ b/winsup/cygwin/net.cc @@ -1912,7 +1912,7 @@ freeifaddrs (struct ifaddrs *ifp) } int -get_ifconf (struct ifconf *ifc, int what) +get_ifconf (struct ifconf *ifc, unsigned int what) { __try { diff --git a/winsup/cygwin/nlsfuncs.cc b/winsup/cygwin/nlsfuncs.cc index b32fecc..f57465a 100644 --- a/winsup/cygwin/nlsfuncs.cc +++ b/winsup/cygwin/nlsfuncs.cc @@ -319,8 +319,7 @@ locale_cmp (const void *a, const void *b) return strcmp (*la, *lb); } -/* Helper function to workaround reallocs which move blocks even if they shrink. - Cygwin's realloc is not doing this, but tcsh's, for instance. All lc_foo +/* Helper function to adjust pointers inside an lc_foo buffer. All lc_foo structures consist entirely of pointers so they are practically pointer arrays. What we do here is just treat the lc_foo pointers as char ** and rebase all char * pointers within, up to the given size of the structure. */ @@ -334,6 +333,28 @@ rebase_locale_buf (const void *ptrv, const void *ptrvend, const char *newbase, *ptrs += newbase - oldbase; } +/* Helper function to shrink an lc_foo buffer, adjusting pointers */ +static int +shrink_locale_buf (const void *ptrv, const void *ptrvend, + char *oldbase, const char *oldend, + char **result) +{ + size_t minsize = oldend - oldbase; + char *tmp = (char *) malloc (minsize); + if (!tmp) + { + free (oldbase); + return -1; + } + + memcpy (tmp, oldbase, minsize); + rebase_locale_buf (ptrv, ptrvend, tmp, oldbase, oldend); + free (oldbase); + + *result = tmp; + return 1; +} + static wchar_t * __getlocaleinfo (wchar_t *loc, LCTYPE type, char **ptr, size_t size) { @@ -687,19 +708,20 @@ __set_lc_time_from_win (const char *name, len += (wcslen (era->era_t_fmt) + 1) * sizeof (wchar_t); len += (wcslen (era->alt_digits) + 1) * sizeof (wchar_t); - /* Make sure data fits into the buffer */ + /* If necessary, grow the buffer to ensure data fits into it */ if (lc_time_ptr + len > lc_time_end) { len = lc_time_ptr + len - new_lc_time_buf; - char *tmp = (char *) realloc (new_lc_time_buf, len); + char *tmp = (char *) malloc (len); if (!tmp) era = NULL; else { - if (tmp != new_lc_time_buf) - rebase_locale_buf (_time_locale, _time_locale + 1, tmp, - new_lc_time_buf, lc_time_ptr); + memcpy (tmp, new_lc_time_buf, MAX_TIME_BUFFER_SIZE); + rebase_locale_buf (_time_locale, _time_locale + 1, tmp, + new_lc_time_buf, lc_time_ptr); lc_time_ptr = tmp + (lc_time_ptr - new_lc_time_buf); + free(new_lc_time_buf); new_lc_time_buf = tmp; lc_time_end = new_lc_time_buf + len; } @@ -752,17 +774,9 @@ __set_lc_time_from_win (const char *name, } } - char *tmp = (char *) realloc (new_lc_time_buf, lc_time_ptr - new_lc_time_buf); - if (!tmp) - { - free (new_lc_time_buf); - return -1; - } - if (tmp != new_lc_time_buf) - rebase_locale_buf (_time_locale, _time_locale + 1, tmp, - new_lc_time_buf, lc_time_ptr); - *lc_time_buf = tmp; - return 1; + return shrink_locale_buf(_time_locale, _time_locale + 1, + new_lc_time_buf, lc_time_ptr, + lc_time_buf); } /* Called from newlib's setlocale() via __ctype_load_locale() if category @@ -824,18 +838,9 @@ __set_lc_ctype_from_win (const char *name, } } - char *tmp = (char *) realloc (new_lc_ctype_buf, - lc_ctype_ptr - new_lc_ctype_buf); - if (!tmp) - { - free (new_lc_ctype_buf); - return -1; - } - if (tmp != new_lc_ctype_buf) - rebase_locale_buf (_ctype_locale, _ctype_locale + 1, tmp, - new_lc_ctype_buf, lc_ctype_ptr); - *lc_ctype_buf = tmp; - return 1; + return shrink_locale_buf(_ctype_locale, _ctype_locale + 1, + new_lc_ctype_buf, lc_ctype_ptr, + lc_ctype_buf); } /* Called from newlib's setlocale() via __numeric_load_locale() if category @@ -900,18 +905,9 @@ __set_lc_numeric_from_win (const char *name, _numeric_locale->codeset = lc_numeric_ptr; lc_numeric_ptr = stpcpy (lc_numeric_ptr, charset) + 1; - char *tmp = (char *) realloc (new_lc_numeric_buf, - lc_numeric_ptr - new_lc_numeric_buf); - if (!tmp) - { - free (new_lc_numeric_buf); - return -1; - } - if (tmp != new_lc_numeric_buf) - rebase_locale_buf (_numeric_locale, _numeric_locale + 1, tmp, - new_lc_numeric_buf, lc_numeric_ptr); - *lc_numeric_buf = tmp; - return 1; + return shrink_locale_buf(_numeric_locale, _numeric_locale + 1, + new_lc_numeric_buf, lc_numeric_ptr, + lc_numeric_buf); } /* Called from newlib's setlocale() via __monetary_load_locale() if category @@ -1039,18 +1035,9 @@ __set_lc_monetary_from_win (const char *name, _monetary_locale->codeset = lc_monetary_ptr; lc_monetary_ptr = stpcpy (lc_monetary_ptr, charset) + 1; - char *tmp = (char *) realloc (new_lc_monetary_buf, - lc_monetary_ptr - new_lc_monetary_buf); - if (!tmp) - { - free (new_lc_monetary_buf); - return -1; - } - if (tmp != new_lc_monetary_buf) - rebase_locale_buf (_monetary_locale, _monetary_locale + 1, tmp, - new_lc_monetary_buf, lc_monetary_ptr); - *lc_monetary_buf = tmp; - return 1; + return shrink_locale_buf(_monetary_locale, _monetary_locale + 1, + new_lc_monetary_buf, lc_monetary_ptr, + lc_monetary_buf); } extern "C" int diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc index bfd338e..a5f5d6e 100644 --- a/winsup/cygwin/pinfo.cc +++ b/winsup/cygwin/pinfo.cc @@ -118,7 +118,7 @@ pinfo_init (char **envp, int envc) DWORD pinfo::status_exit (DWORD x) { - switch (x) + switch ((NTSTATUS) x) { case STATUS_DLL_NOT_FOUND: { diff --git a/winsup/cygwin/posix_timer.cc b/winsup/cygwin/posix_timer.cc index 9d832f2..a336b2b 100644 --- a/winsup/cygwin/posix_timer.cc +++ b/winsup/cygwin/posix_timer.cc @@ -530,6 +530,7 @@ timer_delete (timer_t timerid) __leave; } delete in_tt; + ret = 0; } __except (EFAULT) {} __endtry diff --git a/winsup/cygwin/release/3.5.4 b/winsup/cygwin/release/3.5.4 index 2a5f2b1..90c324b 100644 --- a/winsup/cygwin/release/3.5.4 +++ b/winsup/cygwin/release/3.5.4 @@ -15,3 +15,16 @@ Fixes: - Fix a problem that ldd command against cygwin DLLs sometimes hangs. Addresses: https://cygwin.com/pipermail/cygwin/2024-May/255991.html + +- Fix a problem that pty slave hangs on writing when pty master stops + to read. + Addresses: https://cygwin.com/pipermail/cygwin/2024-June/256178.html + +- Fix conflict on shared name in console between sessions. + Addresses: https://cygwin.com/pipermail/cygwin/2024-April/255893.html + +- Fix an off-by-one in LC_MESSAGE wide character data. + Addresses: https://sourceware.org/pipermail/newlib/2024/021271.html + +- Improve write pipe behaviour in case the pipe buffer is about to be + filled up. diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 new file mode 100644 index 0000000..2ca4572 --- /dev/null +++ b/winsup/cygwin/release/3.5.5 @@ -0,0 +1,35 @@ +Fixes: +------ + +- Fix undesired behaviour of console master thread in win32-input-mode + which is supported by Windows Termainal. + Addresses: https://cygwin.com/pipermail/cygwin/2024-August/256380.html + +- Fix a regression in 3.5.4 that writing to pipe extremely slows down. + Addresses: https://cygwin.com/pipermail/cygwin/2024-August/256398.html + +- Fix pread() and pwrite() EBADF error after fork(). + Addresses: https://sourceware.org/pipermail/cygwin/2024-September/256468.html + +- Fix timer_delete() return value which always indicated failure. + +- Fix lockf() error which occurs when adding a new lock over multiple + locks. + Addresses: https://cygwin.com/pipermail/cygwin/2024-October/256528.html + +- Make lockf() return ENOLCK when the number of locks exceeds + MAX_LOCKF_CNT rather than printing a warning message. + Addresses: https://cygwin.com/pipermail/cygwin/2024-October/256528.html + +- Make console inherit hand over of pseudo console ownership from + parent pty. + Addresses: https://cygwin.com/pipermail/cygwin/2024-February/255388.html + +- Restore pipe blocking mode for non-cygwin apps. + Addresses: https://github.com/git-for-windows/git/issues/5115 + +- Fix a problem that signal handler destroys the FPU context. + Addresses: https://cygwin.com/pipermail/cygwin/2024-October/256503.html + +- Fix type of pthread_sigqueue() first parameter to match Linux. + Addresses: https://cygwin.com/pipermail/cygwin/2024-September/256439.html diff --git a/winsup/cygwin/scripts/gendef b/winsup/cygwin/scripts/gendef index 3b1f8b9..c2ad5c7 100755 --- a/winsup/cygwin/scripts/gendef +++ b/winsup/cygwin/scripts/gendef @@ -213,10 +213,10 @@ sigdelayed: .seh_pushreg %rbx pushq %rax .seh_pushreg %rax - subq \$0x128,%rsp - .seh_stackalloc 0x128 - stmxcsr 0x124(%rsp) - fnstcw 0x120(%rsp) + subq \$0x148,%rsp + .seh_stackalloc 0x148 + stmxcsr 0x13c(%rsp) + fnstenv 0x120(%rsp) movdqa %xmm15,0x110(%rsp) movdqa %xmm14,0x100(%rsp) movdqa %xmm13,0xf0(%rsp) @@ -275,10 +275,9 @@ sigdelayed: movdqa 0xf0(%rsp),%xmm13 movdqa 0x100(%rsp),%xmm14 movdqa 0x110(%rsp),%xmm15 - fninit - fldcw 0x120(%rsp) - ldmxcsr 0x124(%rsp) - addq \$0x128,%rsp + fldenv 0x120(%rsp) + ldmxcsr 0x13c(%rsp) + addq \$0x148,%rsp popq %rax popq %rbx popq %rcx diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc index 725aab9..bc02c3f 100644 --- a/winsup/cygwin/select.cc +++ b/winsup/cygwin/select.cc @@ -584,14 +584,15 @@ no_verify (select_record *, fd_set *, fd_set *, fd_set *) return 0; } -static int -pipe_data_available (int fd, fhandler_base *fh, HANDLE h, bool writing) +ssize_t +pipe_data_available (int fd, fhandler_base *fh, HANDLE h, int flags) { if (fh->get_device () == FH_PIPER) { DWORD nbytes_in_pipe; - if (!writing && PeekNamedPipe (h, NULL, 0, NULL, &nbytes_in_pipe, NULL)) - return nbytes_in_pipe > 0; + if (!(flags & PDA_WRITE) + && PeekNamedPipe (h, NULL, 0, NULL, &nbytes_in_pipe, NULL)) + return nbytes_in_pipe; return -1; } @@ -609,9 +610,17 @@ pipe_data_available (int fd, fhandler_base *fh, HANDLE h, bool writing) access on the write end. */ select_printf ("fd %d, %s, NtQueryInformationFile failed, status %y", fd, fh->get_name (), status); - return writing ? 1 : -1; + switch (flags) + { + case PDA_WRITE: + return 1; + case PDA_SELECT | PDA_WRITE: + return PIPE_BUF; + default: + return -1; + } } - if (writing) + if (flags & PDA_WRITE) { /* If there is anything available in the pipe buffer then signal that. This means that a pipe could still block since you could @@ -638,20 +647,26 @@ pipe_data_available (int fd, fhandler_base *fh, HANDLE h, bool writing) /* Note: Do not use NtQueryInformationFile() for query_hdl because NtQueryInformationFile() seems to interfere with reading pipes in non-cygwin apps. Instead, use PeekNamedPipe() here. */ + /* Note 2: we return the number of available bytes. Select for writing + returns writable *only* if at least PIPE_BUF bytes are left in the + buffer. If we can't fetch the real number of available bytes, the + number of bytes returned depends on the caller. For select we return + PIPE_BUF to fake writability, for writing we return 1 to allow + handling this fact. */ if (fh->get_device () == FH_PIPEW && fpli.WriteQuotaAvailable == 0) { HANDLE query_hdl = ((fhandler_pipe *) fh)->get_query_handle (); if (!query_hdl) query_hdl = ((fhandler_pipe *) fh)->temporary_query_hdl (); - if (!query_hdl) - return 1; /* We cannot know actual write pipe space. */ + if (!query_hdl) /* We cannot know actual write pipe space. */ + return (flags & PDA_SELECT) ? PIPE_BUF : 1; DWORD nbytes_in_pipe; BOOL res = PeekNamedPipe (query_hdl, NULL, 0, NULL, &nbytes_in_pipe, NULL); if (!((fhandler_pipe *) fh)->get_query_handle ()) CloseHandle (query_hdl); /* Close temporary query_hdl */ - if (!res) - return 1; + if (!res) /* We cannot know actual write pipe space. */ + return (flags & PDA_SELECT) ? PIPE_BUF : 1; fpli.WriteQuotaAvailable = fpli.InboundQuota - nbytes_in_pipe; } if (fpli.WriteQuotaAvailable > 0) @@ -659,7 +674,7 @@ pipe_data_available (int fd, fhandler_base *fh, HANDLE h, bool writing) paranoid_printf ("fd %d, %s, write: size %u, avail %u", fd, fh->get_name (), fpli.InboundQuota, fpli.WriteQuotaAvailable); - return 1; + return fpli.WriteQuotaAvailable; } /* TODO: Buffer really full or non-Cygwin reader? */ } @@ -667,7 +682,7 @@ pipe_data_available (int fd, fhandler_base *fh, HANDLE h, bool writing) { paranoid_printf ("fd %d, %s, read avail %u", fd, fh->get_name (), fpli.ReadDataAvailable); - return 1; + return fpli.ReadDataAvailable; } if (fpli.NamedPipeState & FILE_PIPE_CLOSING_STATE) return -1; @@ -715,10 +730,10 @@ peek_pipe (select_record *s, bool from_select) gotone = s->read_ready = true; goto out; } - int n = pipe_data_available (s->fd, fh, h, false); + ssize_t n = pipe_data_available (s->fd, fh, h, PDA_SELECT); /* On PTY masters, check if input from the echo pipe is available. */ if (n == 0 && fh->get_echo_handle ()) - n = pipe_data_available (s->fd, fh, fh->get_echo_handle (), false); + n = pipe_data_available (s->fd, fh, fh->get_echo_handle (), PDA_SELECT); if (n < 0) { @@ -759,9 +774,9 @@ out: gotone += s->except_ready = true; return gotone; } - int n = pipe_data_available (s->fd, fh, h, true); + ssize_t n = pipe_data_available (s->fd, fh, h, PDA_SELECT | PDA_WRITE); select_printf ("write: %s, n %d", fh->get_name (), n); - gotone += s->write_ready = n; + gotone += s->write_ready = (n >= PIPE_BUF); if (n < 0 && s->except_selected) gotone += s->except_ready = true; } @@ -972,9 +987,10 @@ peek_fifo (select_record *s, bool from_select) out: if (s->write_selected) { - int n = pipe_data_available (s->fd, fh, fh->get_handle (), true); + ssize_t n = pipe_data_available (s->fd, fh, fh->get_handle (), + PDA_SELECT | PDA_WRITE); select_printf ("write: %s, n %d", fh->get_name (), n); - gotone += s->write_ready = n; + gotone += s->write_ready = (n >= PIPE_BUF); if (n < 0 && s->except_selected) gotone += s->except_ready = true; } @@ -1398,9 +1414,9 @@ out: HANDLE h = ptys->get_output_handle (); if (s->write_selected) { - int n = pipe_data_available (s->fd, fh, h, true); + ssize_t n = pipe_data_available (s->fd, fh, h, PDA_SELECT | PDA_WRITE); select_printf ("write: %s, n %d", fh->get_name (), n); - gotone += s->write_ready = n; + gotone += s->write_ready = (n >= PIPE_BUF); if (n < 0 && s->except_selected) gotone += s->except_ready = true; } diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 86e4e60..a758bc8 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -1082,7 +1082,7 @@ child_info::proc_retry (HANDLE h) if (!exit_code) return EXITCODE_OK; sigproc_printf ("exit_code %y", exit_code); - switch (exit_code) + switch ((NTSTATUS) exit_code) { case STILL_ACTIVE: /* shouldn't happen */ sigproc_printf ("STILL_ACTIVE? How'd we get here?"); @@ -1475,14 +1475,7 @@ wait_sig (VOID *) } break; case __SIGNONCYGCHLD: - cygheap_fdenum cfd (false); - while (cfd.next () >= 0) - if (cfd->get_dev () == FH_PIPEW) - { - fhandler_pipe *pipe = (fhandler_pipe *)(fhandler_base *) cfd; - if (pipe->need_close_query_hdl ()) - pipe->close_query_handle (); - } + fhandler_pipe::sigproc_worker (); break; } if (clearwait && !have_execed) diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index d01f678..f5a4b91 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -888,6 +888,7 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, ctrl_c_handler(). This insures that setting sigExeced on Ctrl-C key has been completed. */ init_console_handler (false); + fhandler_termios::atexit_func (); myself.exit (EXITCODE_NOSET); break; case _P_WAIT: diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index 0c6f570..9ee9650 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -3301,13 +3301,13 @@ pthread_sigmask (int operation, const sigset_t *set, sigset_t *old_set) } int -pthread_sigqueue (pthread_t *thread, int sig, const union sigval value) +pthread_sigqueue (pthread_t thread, int sig, const union sigval value) { siginfo_t si = {0}; - if (!pthread::is_good_object (thread)) + if (!pthread::is_good_object (&thread)) return EINVAL; - if (!(*thread)->valid) + if (!thread->valid) return ESRCH; si.si_signo = sig; @@ -3315,7 +3315,7 @@ pthread_sigqueue (pthread_t *thread, int sig, const union sigval value) si.si_value = value; si.si_pid = myself->pid; si.si_uid = myself->uid; - return (int) sig_send (NULL, si, (*thread)->cygtls); + return (int) sig_send (NULL, si, thread->cygtls); } /* Cancelability */ diff --git a/winsup/cygwin/tty.cc b/winsup/cygwin/tty.cc index bf7c601..2cd4ae6 100644 --- a/winsup/cygwin/tty.cc +++ b/winsup/cygwin/tty.cc @@ -323,7 +323,7 @@ tty::wait_fwd () thread when the last data is transfered. */ const ULONGLONG sleep_in_nat_pipe = 16; const ULONGLONG time_to_wait = sleep_in_nat_pipe * 2 + 1/* margine */; - ULONGLONG elapsed; + ULONGLONG elapsed = 0; while (fwd_not_empty || (elapsed = GetTickCount64 () - fwd_last_time) < time_to_wait) { diff --git a/winsup/utils/kill.cc b/winsup/utils/kill.cc index fb45e4c..bcabcd4 100644 --- a/winsup/utils/kill.cc +++ b/winsup/utils/kill.cc @@ -73,7 +73,7 @@ print_version () static const char * strsigno (int signo) { - static char sigbuf[8]; + static char sigbuf[32]; if (signo > 0 && signo < SIGRTMIN) return sys_sigabbrev[signo]; |