From 9577467743aac6da917186c9c44b687847df7e3f Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Sun, 25 Aug 2024 11:59:29 +0200 Subject: [PATCH 01/50] bump DLL version to 3.5.5 Signed-off-by: Corinna Vinschen --- winsup/cygwin/include/cygwin/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index 0f87fbc27f..fb821a681b 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. */ From 68a14b66ff2dd6e71497a3a9583253d17e7e790e Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Sat, 31 Aug 2024 18:32:00 +0900 Subject: [PATCH 02/50] Cygwin: console: Disable cons_master_thread in win32-input-mode When win32-input-mode (which is supported by Windows Termainal) is set by "\033[?9001h", cons_master_thread does not work properly and consumes larger and larger memory space. This is because sending event by WriteConsoleInput() is translated into the sequence that is used by win32-input-mode. Due to this behaviour, write-back of the INPUT_RECORDs does not work as expected. With this patch, cons_master_thread is disabled on win32-input-mode where the signal keys such as Ctrl-C, Ctrl-Z etc. never comes. Addresses: https://cygwin.com/pipermail/cygwin/2024-August/256380.html Fixes: ff4440fcf768 ("Cygwin: console: Introduce new thread which handles input signal.") Reported-by: Adamyg Mob Signed-off-by: Takashi Yano (cherry picked from commit 84d77e5918e18170c393407d477140fcf5d3e432) --- winsup/cygwin/fhandler/console.cc | 8 ++++++-- winsup/cygwin/local_includes/fhandler.h | 2 ++ winsup/cygwin/release/3.5.5 | 6 ++++++ 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 winsup/cygwin/release/3.5.5 diff --git a/winsup/cygwin/fhandler/console.cc b/winsup/cygwin/fhandler/console.cc index d4c3f1020b..dc43cd9f59 100644 --- a/winsup/cygwin/fhandler/console.cc +++ b/winsup/cygwin/fhandler/console.cc @@ -818,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: @@ -867,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: @@ -1109,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); @@ -2921,6 +2923,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) diff --git a/winsup/cygwin/local_includes/fhandler.h b/winsup/cygwin/local_includes/fhandler.h index 3d819f49b5..10bc9c7ec8 100644 --- a/winsup/cygwin/local_includes/fhandler.h +++ b/winsup/cygwin/local_includes/fhandler.h @@ -2160,6 +2160,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(). */ diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 new file mode 100644 index 0000000000..a98687c26e --- /dev/null +++ b/winsup/cygwin/release/3.5.5 @@ -0,0 +1,6 @@ +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 From 37ab3e0d55e3ff3932509bfd2f2625c138b18866 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Sun, 1 Sep 2024 04:31:03 +0900 Subject: [PATCH 03/50] Cygwin: pipe: Fix a regression that raw_write() slows down After the commit 7f3c22532577, writing to pipe extremely slows down. This is because cygwait(select_sem, 10, cw_cancel) is called even when write operation is already completed. With this patch, the cygwait() is called only if the write operation is not completed. Addresses: https://cygwin.com/pipermail/cygwin/2024-August/256398.html Fixes: 7f3c22532577 ("Cygwin: pipe: handle signals explicitely in raw_write") Reported-by: Jim Reisert AD1C Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit f78009cb1ccf84cc343cf2441c76196461d87532) --- winsup/cygwin/fhandler/pipe.cc | 6 ++++-- winsup/cygwin/release/3.5.5 | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/winsup/cygwin/fhandler/pipe.cc b/winsup/cygwin/fhandler/pipe.cc index 6658a23e7f..997346877d 100644 --- a/winsup/cygwin/fhandler/pipe.cc +++ b/winsup/cygwin/fhandler/pipe.cc @@ -503,8 +503,9 @@ fhandler_pipe_fifo::raw_write (const void *ptr, size_t len) raise (SIGPIPE); goto out; } - else - cygwait (select_sem, 10, cw_cancel); + /* 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) @@ -512,6 +513,7 @@ fhandler_pipe_fifo::raw_write (const void *ptr, size_t len) 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); diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index a98687c26e..904119a387 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -4,3 +4,6 @@ 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 From 784ce7aff8c92b6b729e8bf5564e582360c24d8c Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Wed, 14 Feb 2024 14:00:34 +0100 Subject: [PATCH 04/50] Cygwin: accommodate gcc -Og option All three warnings produced with -Og are false positives. But given we're using -Werror unconditionally it's better to be safe than sorry. Reported-by: Kevin Ushey Signed-off-by: Corinna Vinschen (cherry picked from commit 2a2a6486a089b90d05b258bd853d136f00cb7c69) --- winsup/cygwin/fhandler/fifo.cc | 2 +- winsup/cygwin/tty.cc | 2 +- winsup/utils/kill.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/winsup/cygwin/fhandler/fifo.cc b/winsup/cygwin/fhandler/fifo.cc index efea508ae5..ee49ce695e 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/tty.cc b/winsup/cygwin/tty.cc index bf7c6010fd..2cd4ae6ed4 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 fb45e4c9dc..bcabcd47c9 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]; From c7fe29f5cb85242ae2607945762f7e0b9af02513 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Fri, 6 Sep 2024 14:19:44 +0900 Subject: [PATCH 05/50] Cygwin: pipe: Restore blocking mode of read pipe on close()/raw_read() If a cygwin app is executed from a non-cygwin app and the cygwin app exits, the read pipe remains in the non-blocking mode because of the commit fc691d0246b9. Due to this behaviour, the non-cygwin app cannot read the pipe correctly after that. Similarly, if a non-cygwin app is executed from a cygwin app and the non-cygwin app exits, the read pipe remains in the blocking mode. With this patch, the blocking mode of the read pipe is stored into a variable was_blocking_read_pipe on set_pipe_non_blocking() when the cygwin app starts and restored on close(). In addition, the pipe mode is set to non-blocking mode in raw_read() if the mode is blocking mode by referring the variable is_blocking_read_pipe as well. is_blocking_read_pipe is a member of fhandler_pipe class and is set by set_pipe_non_blocking(), so if other process sets the pipe mode to blocking mode, the current process cannot know the pipe is blocking mode. Therefore, is_blocking_read_pipe is also set on the signal __SIGNONCYGCHLD, which is sent to the process group when non-cygwin app is started. Addresses: https://github.com/git-for-windows/git/issues/5115 Fixes: fc691d0246b9 ("Cygwin: pipe: Make sure to set read pipe non-blocking for cygwin apps."); Reported-by: isaacag, Johannes Schindelin Reviewed-by: Corinna Vinschen , Ken Brown Signed-off-by: Takashi Yano --- winsup/cygwin/fhandler/pipe.cc | 41 +++++++++++++++++++++++++ winsup/cygwin/local_includes/fhandler.h | 3 ++ winsup/cygwin/sigproc.cc | 9 +----- 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/winsup/cygwin/fhandler/pipe.cc b/winsup/cygwin/fhandler/pipe.cc index 997346877d..3b78cc183e 100644 --- a/winsup/cygwin/fhandler/pipe.cc +++ b/winsup/cygwin/fhandler/pipe.cc @@ -54,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 @@ -62,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 @@ -95,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; } @@ -289,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) @@ -721,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); @@ -1373,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 @@ -1398,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/local_includes/fhandler.h b/winsup/cygwin/local_includes/fhandler.h index 10bc9c7ec8..000004479b 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 @@ class fhandler_pipe: public fhandler_pipe_fifo } 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 diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 99fa3c3425..a758bc8f2c 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -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) From 0281d2c8e294b45a66761fb912095e16f290c556 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Wed, 23 Oct 2024 11:44:34 +0200 Subject: [PATCH 06/50] cygwin: pread/pwrite: prevent EBADF error after fork() If the parent process has already used pread() or pwrite(), these functions fail with EBADF if used on the inherited fd. Ensure that fix_after_fork() is called to invalidate the prw_handle. This issue has been detected by 'stress-ng --pseek 1'. Fixes: c36cd56c548a ("* fhandler.cc (fhandler_base::open): Drop local create_options variable.") Signed-off-by: Christian Franke --- winsup/cygwin/fhandler/disk_file.cc | 3 +++ winsup/cygwin/release/3.5.5 | 3 +++ 2 files changed, 6 insertions(+) diff --git a/winsup/cygwin/fhandler/disk_file.cc b/winsup/cygwin/fhandler/disk_file.cc index 2cfac6be1e..794c8ebcac 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/release/3.5.5 b/winsup/cygwin/release/3.5.5 index 904119a387..d01f31c603 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -7,3 +7,6 @@ Fixes: - 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 From 6e39f397b589539285f1772ada03b7199b3ea7a5 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Wed, 23 Oct 2024 12:24:06 +0200 Subject: [PATCH 07/50] Cygwin: timer_delete: Fix return value timer_delete() always returned failure. This issue has been detected by 'stress-ng --hrtimers 1'. Fixes: 229ea3f23c015 ("Cygwin: posix timers: reimplement using OS timer") Signed-off-by: Christian Franke --- winsup/cygwin/posix_timer.cc | 1 + winsup/cygwin/release/3.5.5 | 2 ++ 2 files changed, 3 insertions(+) diff --git a/winsup/cygwin/posix_timer.cc b/winsup/cygwin/posix_timer.cc index 9d832f2014..a336b2bc2d 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.5 b/winsup/cygwin/release/3.5.5 index d01f31c603..bcc2c661b7 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -10,3 +10,5 @@ Fixes: - 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. From db6ad93d371ce5d1f300886a3a683747e93cf12d Mon Sep 17 00:00:00 2001 From: Fabian Schriever Date: Wed, 11 Sep 2024 16:06:44 +0200 Subject: [PATCH 08/50] powf: Fix the hi+lo decomposition for 2/(3ln2) (FreeBSD) The decomposition needs to be into 12+24 bits of precision for extra- precision multiplication, but was into 13+24 bits. On i386 with -O1 the bug was hidden by accidental extra precision, but on amd64, in 2^32 trials the bug caused about 200000 errors of more than 1 ulp, with a maximum error of about 80 ulps. Now the maximum error in 2^32 trials on amd64 is 0.8573 ulps. It is still 0.8316 ulps on i386 with -O1. The nearby decomposition of 1/ln2 and the decomposition of 2/(3ln2) in the double precision version seem to be sub-optimal but not broken. Reference: https://github.com/freebsd/freebsd-src/commit/b4437c3d322a0f6d23d12b6f76d2fc72d2ff0ec2 Original Author: Bruce Evans --- newlib/libm/math/ef_pow.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/newlib/libm/math/ef_pow.c b/newlib/libm/math/ef_pow.c index 07b225f8cb..4ceba3d247 100644 --- a/newlib/libm/math/ef_pow.c +++ b/newlib/libm/math/ef_pow.c @@ -50,8 +50,8 @@ lg2_h = 6.93145752e-01, /* 0x3f317200 */ lg2_l = 1.42860654e-06, /* 0x35bfbe8c */ ovt = 4.2995665694e-08, /* -(128-log2(ovfl+.5ulp)) */ cp = 9.6179670095e-01, /* 0x3f76384f =2/(3ln2) */ -cp_h = 9.6179199219e-01, /* 0x3f763800 =head of cp */ -cp_l = 4.7017383622e-06, /* 0x369dc3a0 =tail of cp_h */ +cp_h = 9.6191406250e-01f, /* 0x3f764000 =12b of cp */ +cp_l = -1.1736857402e-04f, /* 0xb8f623c6 =tail of cp_h */ ivln2 = 1.4426950216e+00, /* 0x3fb8aa3b =1/ln2 */ ivln2_h = 1.4426879883e+00, /* 0x3fb8aa00 =16b 1/ln2*/ ivln2_l = 7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/ From f21b93098dcdda3f34d847b423c463b5630df4b9 Mon Sep 17 00:00:00 2001 From: Fabian Schriever Date: Wed, 11 Sep 2024 16:06:45 +0200 Subject: [PATCH 09/50] powf: Fixed 2 bugs in the computation /* t_h=ax+bp[k] High */. (FreeBSD) (1) The bit for the 1.0 part of bp[k] was right shifted by 4. This seems to have been caused by a typo in converting e_pow.c to e_powf.c. (2) The lower 12 bits of ax+bp[k] were not discarded, so t_h was actually plain ax+bp[k]. This seems to have been caused by a logic error in the conversion. These bugs gave wrong results like: powf(-1.1, 101.0) = -15158.703 (should be -15158.707) hex values: BF8CCCCD 42CA0000 C66CDAD0 C66CDAD4 Fixing (1) gives a result wrong in the opposite direction (hex C66CDAD8), and fixing (2) gives the correct result. ucbtest has been reporting this particular wrong result on i386 systems with unpatched libraries for 9 years. I finally figured out the extent of the bugs. On i386's they are normally hidden by extra precision. We use the trick of representing floats as a sum of 2 floats (one much smaller) to get extra precision in intermediate calculations without explicitly using more than float precision. This trick is just a pessimization when extra precision is available naturally (as it always is when dealing with IEEE single precision, so the float precision part of the library is mostly misimplemented). (1) and (2) break the trick in different ways, except on i386's it turns out that the intermediate calculations are done in enough precision to mask both the bugs and the limited precision of the float variables (as far as ucbtest can check). ucbtest detects the bugs because it forces float precision, but this is not a normal mode of operation so the bug normally has little effect on i386's. On systems that do float arithmetic in float precision, e.g., amd64's, there is no accidental extra precision and the bugs just give wrong results. Reference: https://github.com/freebsd/freebsd-src/commit/12be4e0d5a54a6750913aee2564d164baa71f0dc Original Author: Bruce Evans --- newlib/libm/math/ef_pow.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/newlib/libm/math/ef_pow.c b/newlib/libm/math/ef_pow.c index 4ceba3d247..c7b1975c38 100644 --- a/newlib/libm/math/ef_pow.c +++ b/newlib/libm/math/ef_pow.c @@ -173,7 +173,8 @@ ivln2_l = 7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/ GET_FLOAT_WORD(is,s_h); SET_FLOAT_WORD(s_h,is&0xfffff000); /* t_h=ax+bp[k] High */ - SET_FLOAT_WORD(t_h,((ix>>1)|0x20000000)+0x0040000+(k<<21)); + is = ((ix >> 1) & 0xfffff000U) | 0x20000000; + SET_FLOAT_WORD(t_h, is + 0x00400000 + (k << 21)); t_l = ax - (t_h-bp[k]); s_l = v*((u-s_h*t_h)-s_h*t_l); /* compute log(ax) */ From 142c3c3ebd21d584257761995fbe00e1e3f92c49 Mon Sep 17 00:00:00 2001 From: Fabian Schriever Date: Wed, 11 Sep 2024 16:06:46 +0200 Subject: [PATCH 10/50] powf: Fixed another precision bug in powf() (FreeBSD) Fixed another precision bug in powf(). This one is in the computation [t=p_l+p_h High]. We multiply t by lg2_h, and want the result to be exact. For the bogus float case of the high-low decomposition trick, we normally discard the lowest 12 bits of the fraction for the high part, keeping 12 bits of precision. That was used for t here, but it doesnt't work because for some reason we only discard the lowest 9 bits in the fraction for lg2_h. Discard another 3 bits of the fraction for t to compensate. This bug gave wrong results like: powf(0.9999999, -2.9999995) = 1.0000002 (should be 1.0000001) hex values: 3F7FFFFF C03FFFFE 3F800002 3F800001 As explained in the log for the previous commit, the bug is normally masked by doing float calculations in extra precision on i386's, but is easily detected by ucbtest on systems that don't have accidental extra precision. Reference: https://github.com/freebsd/freebsd-src/commit/5f20e5ce7f396ad064bfc1f45b8075ea1c0580f9 Original Author: Bruce Evans --- newlib/libm/math/ef_pow.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/newlib/libm/math/ef_pow.c b/newlib/libm/math/ef_pow.c index c7b1975c38..8cf58dbb54 100644 --- a/newlib/libm/math/ef_pow.c +++ b/newlib/libm/math/ef_pow.c @@ -242,7 +242,7 @@ ivln2_l = 7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/ } t = p_l+p_h; GET_FLOAT_WORD(is,t); - SET_FLOAT_WORD(t,is&0xfffff000); + SET_FLOAT_WORD(t,is&0xffff8000); u = t*lg2_h; v = (p_l-(t-p_h))*lg2+t*lg2_l; z = u+v; From b76735a5719375cf9d33d63612092ff8516e99a0 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Sun, 20 Oct 2024 00:59:51 +0900 Subject: [PATCH 11/50] Cygwin: lockf: Fix adding a new lock over multiple locks Previously, adding a new lock by lockf() over multiple existing locks failed. This is due to a bug that lf_setlock() tries to create a lock that has already been created. This patch fixes the issue. Addresses: https://cygwin.com/pipermail/cygwin/2024-October/256528.html Fixes: a998dd705576 ("* flock.cc: Implement all advisory file locking here.") Reported-by: Christian Franke Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano --- winsup/cygwin/flock.cc | 7 ++++--- winsup/cygwin/release/3.5.5 | 4 ++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/winsup/cygwin/flock.cc b/winsup/cygwin/flock.cc index 0f1efa01d4..5550b3a5ba 100644 --- a/winsup/cygwin/flock.cc +++ b/winsup/cygwin/flock.cc @@ -1454,13 +1454,14 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl) /* * Add the new lock before overlap. */ - if (needtolink) { + if (needtolink) + { *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; } diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index bcc2c661b7..ca96edf043 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -12,3 +12,7 @@ Fixes: 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 From f86a181127d96f7dfcf457609cbec998631a837d Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Sun, 20 Oct 2024 01:54:00 +0900 Subject: [PATCH 12/50] Cygwin: lockf: Make lockf() return ENOLCK when too many locks Previously, lockf() printed a warning message when the number of locks per file exceeds the limit (MAX_LOCKF_CNT). This patch makes lockf() return ENOLCK in that case rather than printing the warning message. Addresses: https://cygwin.com/pipermail/cygwin/2024-October/256528.html Fixes: 31390e4ca643 ("(inode_t::get_all_locks_list): Use pre-allocated buffer in i_all_lf instead of allocating every lock. Return pointer to start of linked list of locks.") Reported-by: Christian Franke Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano --- winsup/cygwin/flock.cc | 82 +++++++++++++++++++++++++++++++++---- winsup/cygwin/release/3.5.5 | 4 ++ 2 files changed, 78 insertions(+), 8 deletions(-) diff --git a/winsup/cygwin/flock.cc b/winsup/cygwin/flock.cc index 5550b3a5ba..3821bddd67 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 @@ fhandler_base::lock (int a_op, struct flock *fl) 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; @@ -1456,6 +1495,8 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl) */ if (needtolink) { + if (lock_cnt > MAX_LOCKF_CNT - room_for_clearlock) + return ENOLCK; *prev = lock; lock->lf_next = overlap; lock->create_lock_obj (); @@ -1483,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. */ @@ -1521,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 */ @@ -1528,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/release/3.5.5 b/winsup/cygwin/release/3.5.5 index ca96edf043..2dba4aa8f2 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -16,3 +16,7 @@ Fixes: - 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 From d70081274477a004de2b2aefcc936876b02b161a Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Thu, 31 Oct 2024 11:11:33 +0900 Subject: [PATCH 13/50] Cygwin: console: Inherit pcon hand over from parent pty There was a long-standing issue that pseudo console ownership could not hand over from the process whose ctty is /dev/cons* rather than /dev/pty*. This problem happens when a cygwin app starts non-cygwin app in a pty, then the non-cygwin app starts multiple cygwin apps, and the non-cygwin app ends before the second cygwin apps end. In this case, the stub process of the non-cygwin app hands over the ownership of pcon to one of the second cygwin apps, however, this app does not hand over the ownership of pcon to another second cygwin app. This is due to the fact that the hand-over feature is implemented only in fhandler_pty_slave but not in fhandler_console. With this patch, the second cygwin apps check if their console device is inside a pseudo console, and if so, it tries to hand over the ownership of the pseudo console to anther process that is attached to the same pseudo console. Addresses: https://cygwin.com/pipermail/cygwin/2024-February/255388.html Fixes: 253352e796ff ("Cygwin: pty: Allow multiple apps to enable pseudo console simultaneously.") Reported-by: lmari Lauhakangas , Hossein Nourikhah Signed-off-by: Takashi Yano --- winsup/cygwin/fhandler/console.cc | 64 ++++++++++++++++++++++++- winsup/cygwin/fhandler/pty.cc | 13 ++++- winsup/cygwin/fhandler/termios.cc | 6 +++ winsup/cygwin/local_includes/fhandler.h | 4 ++ winsup/cygwin/local_includes/tty.h | 1 + winsup/cygwin/release/3.5.5 | 4 ++ winsup/cygwin/spawn.cc | 1 + 7 files changed, 90 insertions(+), 3 deletions(-) diff --git a/winsup/cygwin/fhandler/console.cc b/winsup/cygwin/fhandler/console.cc index dc43cd9f59..9cdc13dd23 100644 --- a/winsup/cygwin/fhandler/console.cc +++ b/winsup/cygwin/fhandler/console.cc @@ -60,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. @@ -1894,12 +1898,69 @@ fhandler_console::open (int flags, mode_t) 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 (fhandler_pty_common::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); } @@ -4327,6 +4388,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/pty.cc b/winsup/cygwin/fhandler/pty.cc index fa6bf10961..c40adc2895 100644 --- a/winsup/cygwin/fhandler/pty.cc +++ b/winsup/cygwin/fhandler/pty.cc @@ -102,6 +102,8 @@ fhandler_pty_common::get_console_process_id (DWORD pid, bool match, 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]; @@ -117,7 +119,7 @@ fhandler_pty_common::get_console_process_id (DWORD pid, bool match, res_pri = stub_only ? p->exec_dwProcessId : list[i]; break; } - if (!p && !res && process_alive (list[i]) && stub_only) + if (!p && !res && stub_only) res = list[i]; if (!!p && !res && !stub_only) res = list[i]; @@ -1134,6 +1136,8 @@ process_alive (DWORD pid) inline static bool nat_pipe_owner_self (DWORD pid) { + if (pid == GetCurrentProcessId ()) + return true; return (pid == (myself->exec_dwProcessId ?: myself->dwProcessId)); } @@ -3541,11 +3545,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; } @@ -3573,13 +3582,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/termios.cc b/winsup/cygwin/fhandler/termios.cc index d106955dcc..2acb0e01fa 100644 --- a/winsup/cygwin/fhandler/termios.cc +++ b/winsup/cygwin/fhandler/termios.cc @@ -827,3 +827,9 @@ 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 (); +} diff --git a/winsup/cygwin/local_includes/fhandler.h b/winsup/cygwin/local_includes/fhandler.h index 000004479b..b7b402ff61 100644 --- a/winsup/cygwin/local_includes/fhandler.h +++ b/winsup/cygwin/local_includes/fhandler.h @@ -2022,6 +2022,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 { @@ -2383,6 +2384,9 @@ class fhandler_console: public fhandler_termios 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 (); }; diff --git a/winsup/cygwin/local_includes/tty.h b/winsup/cygwin/local_includes/tty.h index 53fa26b449..2a047d73f9 100644 --- a/winsup/cygwin/local_includes/tty.h +++ b/winsup/cygwin/local_includes/tty.h @@ -178,6 +178,7 @@ class tty: public tty_min friend class fhandler_pty_master; friend class fhandler_pty_slave; friend class tty_min; + friend class fhandler_console; }; class tty_list diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index 2dba4aa8f2..cbaa172748 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -20,3 +20,7 @@ Fixes: - 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 diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index d01f678c3b..f5a4b91d76 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: From 3d364b98c0c31c72ec2df382af2631ca414e4ff8 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Thu, 31 Oct 2024 11:52:26 +0100 Subject: [PATCH 14/50] Cygwin: pipe: fix shift value The expression computing the next-less-power of 2 for the next write when the pipe buffer is getting filled up allows negative shift values. This works on Intel CPUs because the shift expression only evaluates the 5 LSBs, but it's undefined behaviour per the C standard. Use the correct expression to get a positive shift value. Fixes: 170e6badb621 ("Cygwin: pipe: improve writing when pipe buffer is almost full") Reported-by: Takashi Yano Signed-off-by: Corinna Vinschen --- winsup/cygwin/fhandler/pipe.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winsup/cygwin/fhandler/pipe.cc b/winsup/cygwin/fhandler/pipe.cc index 3b78cc183e..6a1ef03b69 100644 --- a/winsup/cygwin/fhandler/pipe.cc +++ b/winsup/cygwin/fhandler/pipe.cc @@ -580,7 +580,7 @@ fhandler_pipe_fifo::raw_write (const void *ptr, size_t len) else if (avail >= PIPE_BUF) len1 = avail & ~(PIPE_BUF - 1); else - len1 = 1 << (31 - __builtin_clzl (avail)); + len1 = 1 << (63 - __builtin_clzl (avail)); short_write_once = true; } if (isclosed ()) /* A signal handler might have closed the fd. */ From 2962922d031ce2e3b32666b434eb9ce75192739c Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Fri, 1 Nov 2024 04:42:18 +0900 Subject: [PATCH 15/50] Add recent pipe change to release note --- winsup/cygwin/release/3.5.5 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index cbaa172748..dbd6b026b4 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -24,3 +24,6 @@ Fixes: - 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 From ea01b87f0f43068fd69658725268ec403ad3b5e9 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Thu, 31 Oct 2024 15:47:35 +0900 Subject: [PATCH 16/50] Cygwin: cygfe: Fix a bug that signal handler destroys fpu states Previously, sigfe had a long-standing problem that the signal handler destroys fpu states. This is caused by fninit instruction in sigdelayed. With this patch, instead of fnstcw/fldcw and fninit, fnstenv/fldenv are used to maintain fpu states. Addresses: https://cygwin.com/pipermail/cygwin/2024-October/256503.html Fixes: ed89fbc3ff11 ("* gendef (sigdelayed (x86_64)): Save and restore FPU control word.") Reported-by: Christian Franke Reviewed-by: Signed-off-by: Takashi Yano --- winsup/cygwin/release/3.5.5 | 3 +++ winsup/cygwin/scripts/gendef | 15 +++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index dbd6b026b4..9cc51dc2e6 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -27,3 +27,6 @@ Fixes: - 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 diff --git a/winsup/cygwin/scripts/gendef b/winsup/cygwin/scripts/gendef index 3b1f8b9dae..c2ad5c75e3 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 From 73168846ea25b6f64cab9fa6c85b13bfeac3b3df Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Tue, 5 Nov 2024 20:20:21 +0900 Subject: [PATCH 17/50] Cygwin: console: Fix open() failure when the console owner calls exec(). Currently, open() tries to attach to the console which is owned by the console owner process. However, when the owner process calls exec(), AttachConsole() to dwProcessId may sometimes fail due to unlucky timing. With this patch, open() tries to attach also to exec_dwProcessId if attaching to dwProcessId fails. That is, open() tries to attach to both the stub process and target process to prevent the above situation. Fixes: 3721a756b0d8 ("Cygwin: console: Make the console accessible from other terminals.") Signed-off-by: Takashi Yano --- winsup/cygwin/fhandler/console.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/winsup/cygwin/fhandler/console.cc b/winsup/cygwin/fhandler/console.cc index 9cdc13dd23..ac47c83747 100644 --- a/winsup/cygwin/fhandler/console.cc +++ b/winsup/cygwin/fhandler/console.cc @@ -84,6 +84,10 @@ fhandler_console::attach_console (pid_t owner, bool *err) DWORD attached = fhandler_pty_common::get_console_process_id (p->dwProcessId, true, false, false); + if (!attached) + attached = + fhandler_pty_common::get_console_process_id (p->exec_dwProcessId, + true, false, false); if (!attached) { resume_pid = @@ -91,6 +95,8 @@ fhandler_console::attach_console (pid_t owner, bool *err) false, false, false); FreeConsole (); BOOL r = AttachConsole (p->dwProcessId); + if (!r) + r = AttachConsole (p->exec_dwProcessId); if (!r) { if (resume_pid) From f307544150ddf3de78a7edb3f04a983c3efc6c19 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Wed, 6 Nov 2024 10:19:59 +0900 Subject: [PATCH 18/50] Cygwin: console: Re-fix open() failure on exec() by console owner Previous fix (commit df0953aa298c) fixes only a part of the problem. Since exec() overrides the cygwin pid of the caller process, it makes console owner handling complex. This patch makes console use Windows pid as the owner pid (con.owner) instead of cygwin pid to make the handling simpler. Fixes: df0953aa298c ("Cygwin: console: Fix open() failure when the console owner calls exec().") Signed-off-by: Takashi Yano (cherry picked from commit 90ddab98780da0e888ff09987d4651107c0f48d6) --- winsup/cygwin/fhandler/console.cc | 86 ++++++++++--------------- winsup/cygwin/fhandler/pty.cc | 73 --------------------- winsup/cygwin/fhandler/termios.cc | 72 +++++++++++++++++++++ winsup/cygwin/local_includes/fhandler.h | 19 +++--- 4 files changed, 117 insertions(+), 133 deletions(-) diff --git a/winsup/cygwin/fhandler/console.cc b/winsup/cygwin/fhandler/console.cc index ac47c83747..7ac9265547 100644 --- a/winsup/cygwin/fhandler/console.cc +++ b/winsup/cygwin/fhandler/console.cc @@ -75,43 +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) - attached = - fhandler_pty_common::get_console_process_id (p->exec_dwProcessId, - true, false, false); - if (!attached) + resume_pid = + get_console_process_id (myself->dwProcessId, 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) - r = AttachConsole (p->exec_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; @@ -120,11 +110,11 @@ fhandler_console::detach_console (DWORD resume_pid, pid_t owner) FreeConsole (); AttachConsole (resume_pid); } - else if (myself->pid != owner) + else if (myself->dwProcessId != owner) FreeConsole (); } -pid_t +DWORD fhandler_console::get_owner () { return con.owner; @@ -143,14 +133,14 @@ static class write_pending_buffer { 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) { @@ -405,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 == myself->dwProcessId) { DWORD total_read, n, i; @@ -719,7 +709,7 @@ fhandler_console::set_unit () unit = device::minor (cs->tty_min_state.ntty); shared_console_info[unit] = cs; if (created) - con.owner = myself->pid; + con.owner = myself->dwProcessId; } } } @@ -927,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 == myself->dwProcessId) ? 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 == myself->dwProcessId); } /* Return the tty structure associated with a given tty number. If the @@ -1043,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. */ @@ -1783,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 = myself->dwProcessId; /* Open the input handle as handle_ */ bool err = false; @@ -1853,7 +1838,7 @@ fhandler_console::open (int flags, mode_t) set_open_status (); - if (myself->pid == con.owner && wincap.has_con_24bit_colors ()) + if (myself->dwProcessId == con.owner && wincap.has_con_24bit_colors ()) { bool is_legacy = false; DWORD dwMode; @@ -1884,7 +1869,7 @@ 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 (myself->dwProcessId == con.owner) { if (GetModuleHandle ("ConEmuHk64.dll")) hook_conemu_cygwin_connector (); @@ -1914,8 +1899,7 @@ fhandler_console::setup_pcon_hand_over () if (!cygwin_shared->tty[i]->pcon_activated) continue; DWORD owner = cygwin_shared->tty[i]->nat_pipe_owner_pid; - if (fhandler_pty_common::get_console_process_id - (owner, true, false, false, false)) + if (get_console_process_id (owner, true, false, false, false)) { inside_pcon = true; atexit (fhandler_console::pcon_hand_over_proc); @@ -2001,7 +1985,7 @@ fhandler_console::close () &obi, sizeof obi, NULL); if ((NT_SUCCESS (status) && obi.HandleCount == 1 && (dev_t) myself->ctty == get_device ()) - || myself->pid == con.owner) + || myself->dwProcessId == con.owner) { /* Cleaning-up console mode for cygwin apps. */ set_output_mode (tty::restore, &get_ttyp ()->ti, &handle_set); @@ -2010,7 +1994,7 @@ fhandler_console::close () } } - if (shared_console_info[unit] && con.owner == myself->pid) + if (shared_console_info[unit] && con.owner == myself->dwProcessId) { if (master_thread_started) { @@ -2019,7 +2003,7 @@ fhandler_console::close () thread_sync_event = OpenEvent (MAXIMUM_ALLOWED, FALSE, name); if (thread_sync_event) { - con.owner = MAX_PID + 1; + con.owner = (DWORD) -1; WaitForSingleObject (thread_sync_event, INFINITE); CloseHandle (thread_sync_event); } @@ -3508,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; diff --git a/winsup/cygwin/fhandler/pty.cc b/winsup/cygwin/fhandler/pty.cc index c40adc2895..4f0f718127 100644 --- a/winsup/cygwin/fhandler/pty.cc +++ b/winsup/cygwin/fhandler/pty.cc @@ -74,60 +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 (!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; -} - 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. */ @@ -1114,25 +1060,6 @@ 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) { diff --git a/winsup/cygwin/fhandler/termios.cc b/winsup/cygwin/fhandler/termios.cc index 2acb0e01fa..585e6ac4ac 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 @@ -833,3 +834,74 @@ 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/local_includes/fhandler.h b/winsup/cygwin/local_includes/fhandler.h index b7b402ff61..88a6b7d47b 100644 --- a/winsup/cygwin/local_includes/fhandler.h +++ b/winsup/cygwin/local_includes/fhandler.h @@ -1970,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; }; @@ -2093,7 +2098,7 @@ enum cltype class dev_console { - pid_t owner; + DWORD owner; bool is_legacy; bool orig_virtual_terminal_processing_mode; @@ -2243,7 +2248,7 @@ class fhandler_console: public fhandler_termios 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;} @@ -2368,9 +2373,9 @@ class fhandler_console: public fhandler_termios 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); @@ -2434,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); From 92f4e103d187f0b5a27d1a93d2cc22a9909ece68 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Wed, 6 Nov 2024 22:43:13 +0900 Subject: [PATCH 19/50] Cygwin: console: Use GetCurrentProcessId() instead of myself->dwProcessId The commit 90ddab98780d uses myself->dwProcessId to get windows pid. However, it will be overridden in stub process if exec() is called. With this patch, GetCurrentProcessId() instead of myself->dwProcessId. Fixes: 90ddab98780d ("Cygwin: console: Re-fix open() failure on exec() by console owner") Signed-off-by: Takashi Yano (cherry picked from commit 8ee8b0c974d723d618182fbbdeb1e9186b69c6f3) --- winsup/cygwin/fhandler/console.cc | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/winsup/cygwin/fhandler/console.cc b/winsup/cygwin/fhandler/console.cc index 7ac9265547..4efba61e25 100644 --- a/winsup/cygwin/fhandler/console.cc +++ b/winsup/cygwin/fhandler/console.cc @@ -85,7 +85,7 @@ fhandler_console::attach_console (DWORD owner, bool *err) if (!attached) { resume_pid = - get_console_process_id (myself->dwProcessId, false, false, false); + get_console_process_id (GetCurrentProcessId (), false, false, false); FreeConsole (); BOOL r = AttachConsole (owner); if (!r) @@ -110,7 +110,7 @@ fhandler_console::detach_console (DWORD resume_pid, DWORD owner) FreeConsole (); AttachConsole (resume_pid); } - else if (myself->dwProcessId != owner) + else if (GetCurrentProcessId () != owner) FreeConsole (); } @@ -395,7 +395,7 @@ fhandler_console::cons_master_thread (handle_set_t *p, tty *ttyp) } }; termios &ti = ttyp->ti; - while (con.owner == myself->dwProcessId) + while (con.owner == GetCurrentProcessId ()) { DWORD total_read, n, i; @@ -709,7 +709,7 @@ fhandler_console::set_unit () unit = device::minor (cs->tty_min_state.ntty); shared_console_info[unit] = cs; if (created) - con.owner = myself->dwProcessId; + con.owner = GetCurrentProcessId (); } } } @@ -917,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->dwProcessId) ? 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->dwProcessId); + set_disable_master_thread (con.owner == GetCurrentProcessId ()); } /* Return the tty structure associated with a given tty number. If the @@ -1774,7 +1774,7 @@ fhandler_console::open (int flags, mode_t) acquire_output_mutex (mutex_timeout); if (!process_alive (con.owner)) - con.owner = myself->dwProcessId; + con.owner = GetCurrentProcessId (); /* Open the input handle as handle_ */ bool err = false; @@ -1838,7 +1838,7 @@ fhandler_console::open (int flags, mode_t) set_open_status (); - if (myself->dwProcessId == con.owner && wincap.has_con_24bit_colors ()) + if (GetCurrentProcessId () == con.owner && wincap.has_con_24bit_colors ()) { bool is_legacy = false; DWORD dwMode; @@ -1869,7 +1869,7 @@ fhandler_console::open (int flags, mode_t) debug_printf ("opened conin$ %p, conout$ %p", get_handle (), get_output_handle ()); - if (myself->dwProcessId == con.owner) + if (GetCurrentProcessId () == con.owner) { if (GetModuleHandle ("ConEmuHk64.dll")) hook_conemu_cygwin_connector (); @@ -1983,9 +1983,9 @@ fhandler_console::close () 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->dwProcessId == con.owner) + if (NT_SUCCESS (status) + && obi.HandleCount <= (myself->cygstarted ? 2 : 3) + && (dev_t) myself->ctty == get_device ()) { /* Cleaning-up console mode for cygwin apps. */ set_output_mode (tty::restore, &get_ttyp ()->ti, &handle_set); @@ -1994,7 +1994,7 @@ fhandler_console::close () } } - if (shared_console_info[unit] && con.owner == myself->dwProcessId) + if (shared_console_info[unit] && con.owner == GetCurrentProcessId ()) { if (master_thread_started) { From 38ab2b77e325bf5c9d25cb832f8b80c58ff80299 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Fri, 8 Nov 2024 20:02:35 +0900 Subject: [PATCH 20/50] Cygwin: console: Fix clean up conditions in close() Previously, the condition to clean up input/output mode was based on wrong premise. This patch fixes that. Fixes: 8ee8b0c974d7 ("Cygwin: console: Use GetCurrentProcessId() instead of myself->dwProcessId") Signed-off-by: Takashi Yano (cherry picked from commit 30d266947842fec82cae9a190bc8b5bf2e108cd0) --- winsup/cygwin/fhandler/console.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/winsup/cygwin/fhandler/console.cc b/winsup/cygwin/fhandler/console.cc index 4efba61e25..2651e49a62 100644 --- a/winsup/cygwin/fhandler/console.cc +++ b/winsup/cygwin/fhandler/console.cc @@ -1976,7 +1976,8 @@ 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; @@ -1984,8 +1985,7 @@ fhandler_console::close () status = NtQueryObject (get_handle (), ObjectBasicInformation, &obi, sizeof obi, NULL); if (NT_SUCCESS (status) - && obi.HandleCount <= (myself->cygstarted ? 2 : 3) - && (dev_t) myself->ctty == get_device ()) + && obi.HandleCount == (con.owner == GetCurrentProcessId () ? 2 : 3)) { /* Cleaning-up console mode for cygwin apps. */ set_output_mode (tty::restore, &get_ttyp ()->ti, &handle_set); From 9dad29c238bfce017f54915b90a1c2c4fcac9529 Mon Sep 17 00:00:00 2001 From: Shaobo Song Date: Sun, 10 Nov 2024 12:15:04 +0800 Subject: [PATCH 21/50] Cygwin: pthread: Correct pthread_cleanup macros to avoid potential syntax errors This commit revises `pthread_cleanup_push` and `pthread_cleanup_pop` macros to use a `do { ... } while(0)` wrapper, preventing syntax errors when used in certain contexts. The original code could fail when they are wrapped within a `do { ... } while(0)`, causing unintended behavior or compilation issues. Example of error: #include #define pthread_cleanup_push_wrapper(_fn, _arg) do { \ pthread_cleanup_push(_fn, _arg); \ } while (0) #define pthread_cleanup_pop_wrapper(_execute) do { \ pthread_cleanup_pop(_execute); \ } while (0) void cleanup_fn (void *arg) {} void *thread_func (void *arg) { pthread_cleanup_push_wrapper(cleanup_fn, NULL); pthread_cleanup_pop_wrapper(1); return NULL; } int main (int argc, char **argv) { pthread_t thread_id; pthread_create(&thread_id, NULL, thread_func, NULL); } This would fail due to unmatched braces in the macro expansion. The new structure ensures the macro expands correctly in all cases. Fixes: 007276b30e0a ("* cygwin.din: Add _pthread_cleanup_push and _pthread_cleanup_pop.") Signed-off-by: Shaobo Song --- winsup/cygwin/include/pthread.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/winsup/cygwin/include/pthread.h b/winsup/cygwin/include/pthread.h index 66d367d622..cf2fcb04b3 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 *); From b9060e06a6e4f52ad3c27488b32f7a825114e6b4 Mon Sep 17 00:00:00 2001 From: Mark Geisert Date: Mon, 11 Nov 2024 22:38:29 -0800 Subject: [PATCH 22/50] Cygwin: Change pthread_sigqueue() to accept thread id Change the first parameter of pthread_sigqueue() to be a thread id rather than a thread pointer. The change is to match the Linux implementation of this function. The user-visible function prototype is changed in include/pthread.h. The pthread_sigqueue() function is modified to work with a passed-in thread id rather than an indirect thread pointer as before. (It used to be "pthread_t *thread", i.e., class pthread **.) The release note for Cygwin 3.5.5 is updated. Reported-by: Christian Franke Addresses: https://cygwin.com/pipermail/cygwin/2024-September/256439.html Signed-off-by: Mark Geisert Fixes: 50350cafb375 ("* cygwin.din (pthread_sigqueue): Export.") (cherry picked from commit 1e8c92e21d386d2e4a29fa92e8258979ff19ae6b) --- winsup/cygwin/include/pthread.h | 2 +- winsup/cygwin/release/3.5.5 | 3 +++ winsup/cygwin/thread.cc | 8 ++++---- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/winsup/cygwin/include/pthread.h b/winsup/cygwin/include/pthread.h index cf2fcb04b3..8e296303d7 100644 --- a/winsup/cygwin/include/pthread.h +++ b/winsup/cygwin/include/pthread.h @@ -247,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/release/3.5.5 b/winsup/cygwin/release/3.5.5 index 9cc51dc2e6..2ca4572db7 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -30,3 +30,6 @@ Fixes: - 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/thread.cc b/winsup/cygwin/thread.cc index 0c6f570322..9ee96504b8 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 */ From 22474a6e5d134407db3951e65c5b89a4bd700580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20=C3=9Cbelacker?= Date: Sat, 16 Nov 2024 18:09:50 +0100 Subject: [PATCH 23/50] Cygwin: check_dir_not_empty: Avoid leaving the allocated buffer. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pointer pfni gets allocated the buffer at the begin, and is used in the NtQueryDirectoryFile call before the loops. In the loop the pointer pfni is also used as iterator. Therefore it holds no longer the initial buffer at the call to NtQueryDirectoryFile in the while conditition at the bottom. Fixes: 28fa2a72f8106 ("* syscalls.cc (check_dir_not_empty): Check surplus directory entries") Co-authored-by: Corinna Vinschen Signed-off-by: Bernhard Übelacker (cherry picked from commit dbb8069df56cb68ea1167b3bc0ceb66fa6c35d3f) --- winsup/cygwin/release/3.5.5 | 3 +++ winsup/cygwin/syscalls.cc | 10 ++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index 2ca4572db7..3088f8682b 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -33,3 +33,6 @@ Fixes: - Fix type of pthread_sigqueue() first parameter to match Linux. Addresses: https://cygwin.com/pipermail/cygwin/2024-September/256439.html + +- Fix potential stack corruption in rmdir() in a border case. + Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256774.html diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 9d88b60b0f..1d9308ef46 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -617,9 +617,10 @@ check_dir_not_empty (HANDLE dir, path_conv &pc) IO_STATUS_BLOCK io; const ULONG bufsiz = 3 * sizeof (FILE_NAMES_INFORMATION) + 3 * NAME_MAX * sizeof (WCHAR); - PFILE_NAMES_INFORMATION pfni = (PFILE_NAMES_INFORMATION) - alloca (bufsiz); - NTSTATUS status = NtQueryDirectoryFile (dir, NULL, NULL, 0, &io, pfni, + PFILE_NAMES_INFORMATION pfni_buf = (PFILE_NAMES_INFORMATION) + alloca (bufsiz); + PFILE_NAMES_INFORMATION pfni; + NTSTATUS status = NtQueryDirectoryFile (dir, NULL, NULL, 0, &io, pfni_buf, bufsiz, FileNamesInformation, FALSE, NULL, TRUE); if (!NT_SUCCESS (status)) @@ -631,6 +632,7 @@ check_dir_not_empty (HANDLE dir, path_conv &pc) int cnt = 1; do { + pfni = pfni_buf; while (pfni->NextEntryOffset) { if (++cnt > 2) @@ -677,7 +679,7 @@ check_dir_not_empty (HANDLE dir, path_conv &pc) pfni = (PFILE_NAMES_INFORMATION) ((caddr_t) pfni + pfni->NextEntryOffset); } } - while (NT_SUCCESS (NtQueryDirectoryFile (dir, NULL, NULL, 0, &io, pfni, + while (NT_SUCCESS (NtQueryDirectoryFile (dir, NULL, NULL, 0, &io, pfni_buf, bufsiz, FileNamesInformation, FALSE, NULL, FALSE))); return STATUS_SUCCESS; From c4102f82ddd97f77e32bda7aba84d5d4cc4028a7 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Thu, 14 Nov 2024 00:44:41 +0900 Subject: [PATCH 24/50] Cygwin: lockf: Fix access violation in lf_clearlock(). The commit ae181b0ff122 has a bug that the pointer is referred bofore NULL check in the function lf_clearlock(). This patch fixes that. Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256750.html Fixes: ae181b0ff122 ("Cygwin: lockf: Make lockf() return ENOLCK when too many locks") Reported-by: Sebastian Feld Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit e7ef920d7d0dcff8cfe7a0c914f803b8c78900bb) --- winsup/cygwin/flock.cc | 6 ++++-- winsup/cygwin/release/3.5.5 | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/winsup/cygwin/flock.cc b/winsup/cygwin/flock.cc index 3821bddd67..794e66bd7e 100644 --- a/winsup/cygwin/flock.cc +++ b/winsup/cygwin/flock.cc @@ -1524,6 +1524,10 @@ lf_clearlock (lockf_t *unlock, lockf_t **clean, HANDLE fhdl) lockf_t *lf = *head; lockf_t *overlap, **prev; int ovcase; + + if (lf == NOLOCKF) + return 0; + inode_t *node = lf->lf_inode; tmp_pathbuf tp; node->i_all_lf = (lockf_t *) tp.w_get (); @@ -1531,8 +1535,6 @@ lf_clearlock (lockf_t *unlock, lockf_t **clean, HANDLE fhdl) 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))) { diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index 3088f8682b..13982632b0 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -36,3 +36,6 @@ Fixes: - Fix potential stack corruption in rmdir() in a border case. Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256774.html + +- Fix access violation in lf_clearlock() called from flock(). + Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256750.html From 67b31bc4ae1fc60d0407210a52e39bcbea0dc6f5 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Fri, 15 Nov 2024 21:58:22 +0900 Subject: [PATCH 25/50] Cygwin: flock: Fix overlap handling in lf_setlock() and lf_clearlock() Currently, create_lock_obj() can create multiple locks with the same lock range that have different version number. However, lf_setlock() and lf_clearlock() cannot handle this case appropriately. With this patch, make lf_setlock() and lf_clearlock() find overlap again even when ovcase = 1 (lock and overlap have the same lock range). Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256750.html Fixes: 2e560a092c1c ("* flock.cc (LOCK_OBJ_NAME_LEN): Change to accommodate extra lf_ver field.") Reported-by: Sebastian Feld Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit 8dee07a1f12682307be07e12a7fd8d5c8ecc1e2b) --- winsup/cygwin/flock.cc | 31 ++++++++++++++++++------------- winsup/cygwin/release/3.5.5 | 3 +++ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/winsup/cygwin/flock.cc b/winsup/cygwin/flock.cc index 794e66bd7e..b41cba5c70 100644 --- a/winsup/cygwin/flock.cc +++ b/winsup/cygwin/flock.cc @@ -1410,12 +1410,16 @@ lf_setlock (lockf_t *lock, inode_t *node, lockf_t **clean, HANDLE fhdl) */ if (lock_cnt > MAX_LOCKF_CNT - room_for_clearlock) return ENOLCK; + /* Do not create a lock here. It should be done after all + overlaps have been removed. */ lf_wakelock (overlap, fhdl); - overlap->lf_type = lock->lf_type; - overlap->create_lock_obj (); - lock->lf_next = *clean; - *clean = lock; - break; + *prev = overlap->lf_next; + overlap->lf_next = *clean; + *clean = overlap; + /* We may have multiple versions (lf_ver) having same lock range. + Therefore, we need to find overlap repeatedly. (originally, + just 'break' here. */ + continue; case 2: /* overlap contains lock */ /* @@ -1563,10 +1567,16 @@ lf_clearlock (lockf_t *unlock, lockf_t **clean, HANDLE fhdl) switch (ovcase) { case 1: /* overlap == lock */ + case 3: /* lock contains overlap */ *prev = overlap->lf_next; + lf = overlap->lf_next; overlap->lf_next = *clean; *clean = overlap; - break; + first_loop = false; + /* We may have multiple versions (lf_ver) having same lock range. + Therefore, we need to find overlap repeatedly. (originally, + just 'break' here. */ + continue; case 2: /* overlap contains lock: split it */ if (overlap->lf_start == unlock->lf_start) @@ -1582,13 +1592,8 @@ lf_clearlock (lockf_t *unlock, lockf_t **clean, HANDLE fhdl) overlap->lf_next->create_lock_obj (); break; - case 3: /* lock contains overlap */ - *prev = overlap->lf_next; - lf = overlap->lf_next; - overlap->lf_next = *clean; - *clean = overlap; - first_loop = false; - continue; + /* case 3: */ /* lock contains overlap */ + /* Merged into case 1 */ case 4: /* overlap starts before lock */ overlap->lf_end = unlock->lf_start - 1; diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index 13982632b0..b70b91ed81 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -39,3 +39,6 @@ Fixes: - Fix access violation in lf_clearlock() called from flock(). Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256750.html + +- Fix NtCreateEvent() error in create_lock_ob() called from flock(). + Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256750.html From 2196f93fdadccebd71792ad190cfdf054d635994 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Wed, 20 Nov 2024 16:21:03 +0100 Subject: [PATCH 26/50] Cygwin: SetThreadName: avoid spurious debug message The following debug message occassionally shows up in strace output: SetThreadName: SetThreadDescription() failed. 00000000 10000000 The HRESULT of 0x10000000 is not an error, rather the set bit just indicates that this HRESULT has been created from an NTSTATUS value. Use the IS_ERROR() macro instead of just checking for S_OK. Fixes: d4689b99c686 ("Cygwin: Set threadnames with SetThreadDescription()") Signed-off-by: Corinna Vinschen (cherry picked from commit 21a2c9db6952954608cdf92638b411b15e7606c6) --- winsup/cygwin/miscfuncs.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winsup/cygwin/miscfuncs.cc b/winsup/cygwin/miscfuncs.cc index 767384faa9..4220f62757 100644 --- a/winsup/cygwin/miscfuncs.cc +++ b/winsup/cygwin/miscfuncs.cc @@ -353,7 +353,7 @@ SetThreadName (DWORD dwThreadID, const char* threadName) WCHAR buf[bufsize]; bufsize = MultiByteToWideChar (CP_UTF8, 0, threadName, -1, buf, bufsize); HRESULT hr = SetThreadDescription (hThread, buf); - if (hr != S_OK) + if (IS_ERROR (hr)) { debug_printf ("SetThreadDescription() failed. %08x %08x\n", GetLastError (), hr); From 46474ecf5773bcfa216fe4943b8348f3aeb2bfcc Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Mon, 18 Nov 2024 00:07:12 +0900 Subject: [PATCH 27/50] Cygwin: sigtimedwait: Fix segfault when timeout is used Previously, two bugs exist in sigtimedwait(). One is, that since _my_tls.sigwait_mask was left non-zero if the signal arrives after the timeout, sigpacket::process() would wrongly try to handle it. The other is if a timeout occurs after sigpacket::process() is called, but not completed yet, the signal handler can be called accidentally. If the signal handler is set to SIG_DFL or SIG_IGN, access violation will occur in both cases. With this patch, in sigwait_common(), check if sigwait_mask == 0 to confirm that sigpacket::process() cleared it. In this case, do not treat WAIT_TIMEOUT, but call cygwait() again to retrieve the signal. Furthermore, sigpacket::process() checks whether timeout occurs in sigwait_common() and if timeout already happens, do not treat the signal as waited. In both cases, to avoid race issues, the code is guarded by cygtls::lock(). Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256762.html Fixes: 24ff42d79aab ("Cygwin: Implement sigtimedwait") Reported-by: Christian Franke Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit 26144e4008cd8f7288f3387eea697bba4006e16f) --- winsup/cygwin/exceptions.cc | 5 ++++- winsup/cygwin/release/3.5.5 | 3 +++ winsup/cygwin/signal.cc | 12 ++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 3195d5719a..60c1f594f8 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -1527,11 +1527,14 @@ sigpacket::process () if ((HANDLE) *tls) tls->signal_debugger (si); - if (issig_wait) + tls->lock (); + if (issig_wait && tls->sigwait_mask != 0) { tls->sigwait_mask = 0; + tls->unlock (); goto dosig; } + tls->unlock (); if (handler == SIG_IGN) { diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index b70b91ed81..d91f2b92cd 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -42,3 +42,6 @@ Fixes: - Fix NtCreateEvent() error in create_lock_ob() called from flock(). Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256750.html + +- Fix segfault in sigtimedwait() when using timeout. + Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256762.html diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc index 77152910b5..9ee6cf9959 100644 --- a/winsup/cygwin/signal.cc +++ b/winsup/cygwin/signal.cc @@ -615,6 +615,7 @@ sigwait_common (const sigset_t *set, siginfo_t *info, PLARGE_INTEGER waittime) set_signal_mask (_my_tls.sigwait_mask, *set); sig_dispatch_pending (true); +do_wait: switch (cygwait (NULL, waittime, cw_sig_eintr | cw_cancel | cw_cancel_self)) { @@ -640,6 +641,17 @@ sigwait_common (const sigset_t *set, siginfo_t *info, PLARGE_INTEGER waittime) } break; case WAIT_TIMEOUT: + _my_tls.lock (); + if (_my_tls.sigwait_mask == 0) + { + /* sigpacket::process() already started. + Will surely be signalled soon. */ + waittime = cw_infinite; + _my_tls.unlock (); + goto do_wait; + } + _my_tls.sigwait_mask = 0; + _my_tls.unlock (); set_errno (EAGAIN); break; default: From d06ba04550f96ae30daf38019ec80c99a39cf3f7 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Mon, 25 Nov 2024 15:02:36 +0100 Subject: [PATCH 28/50] Cygwin: sched_getscheduler: fix error handling Fixes: 6b2a2aa4af1e ("Add missing files.") Signed-off-by: Christian Franke --- winsup/cygwin/sched.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/sched.cc b/winsup/cygwin/sched.cc index 845fcef570..39d0ed96bb 100644 --- a/winsup/cygwin/sched.cc +++ b/winsup/cygwin/sched.cc @@ -140,7 +140,10 @@ int sched_getscheduler (pid_t pid) { if (pid < 0) - return ESRCH; + { + set_errno (EINVAL); + return -1; + } else return SCHED_FIFO; } From 96d729bc00a13a0c870701262745209e1ad59456 Mon Sep 17 00:00:00 2001 From: Christian Franke Date: Wed, 27 Nov 2024 16:39:37 +0100 Subject: [PATCH 29/50] Cygwin: sched_setscheduler: allow changes of the priority Behave like sched_setparam() if the requested policy is identical to the fixed value (SCHED_FIFO) returned by sched_getscheduler(). Fixes: 9a08b2c02eea ("* sched.cc: New file. Implement sched*.") Signed-off-by: Christian Franke (cherry picked from commit 522f3e921aa034c6a146021a918ce8b479a9111e) --- winsup/cygwin/release/3.5.5 | 3 +++ winsup/cygwin/sched.cc | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index d91f2b92cd..d41d168c6e 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -45,3 +45,6 @@ Fixes: - Fix segfault in sigtimedwait() when using timeout. Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256762.html + +- sched_setscheduler(2) allows to change the priority if the policy is + equal to the value returned by sched_getscheduler(2). diff --git a/winsup/cygwin/sched.cc b/winsup/cygwin/sched.cc index 39d0ed96bb..a37e4f8b2f 100644 --- a/winsup/cygwin/sched.cc +++ b/winsup/cygwin/sched.cc @@ -402,8 +402,11 @@ int sched_setscheduler (pid_t pid, int policy, const struct sched_param *param) { + if (policy == SCHED_FIFO) /* returned by sched_getscheduler. */ + return sched_setparam (pid, param); + /* on win32, you can't change the scheduler. Doh! */ - set_errno (ENOSYS); + set_errno (EINVAL); return -1; } From 9af37caf780efa49b21fe1be8abc13037ce495ad Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Wed, 4 Dec 2024 13:00:39 +0900 Subject: [PATCH 30/50] Cygwin: termios: Trim buffer size for GetConsoleProcessList() Currently, the buffer of 128KB is passed to GetConsoleProcessList(). This causes page fault in the select() loop for console due to: https://github.com/microsoft/terminal/issues/18264 because the previous code calls GetConsoleProcessList() with large buffer and PeekConsoleInput() with small buffer alternately. With this patch, the minimum buffer size is used that is determined by GetConsoleProcessList() with small buffer passed. Addresses: https://cygwin.com/pipermail/cygwin/2024-December/256841.html Fixes: 72770148ad0a ("Cygwin: pty: Prevent pty from changing code page of parent console.") Reported-by: Steven Buehler Signed-off-by: Takashi Yano (cherry picked from commit 1a49c17840660bc0e493b7db2d9ce5289906049d) --- winsup/cygwin/fhandler/termios.cc | 14 ++++++++++++-- winsup/cygwin/release/3.5.5 | 3 +++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/winsup/cygwin/fhandler/termios.cc b/winsup/cygwin/fhandler/termios.cc index 585e6ac4ac..3cbdf7fca0 100644 --- a/winsup/cygwin/fhandler/termios.cc +++ b/winsup/cygwin/fhandler/termios.cc @@ -870,8 +870,18 @@ fhandler_termios::get_console_process_id (DWORD pid, bool match, 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) + DWORD buf_size1 = 1; + DWORD num; + /* The buffer of too large size does not seem to be expected by new condrv. + https://github.com/microsoft/terminal/issues/18264#issuecomment-2515448548 + Use the minimum buffer size in the loop. */ + while ((num = GetConsoleProcessList (list, buf_size1)) > buf_size1) + { + if (num > buf_size) + return 0; + buf_size1 = num; + } + if (num == 0) return 0; DWORD res_pri = 0, res = 0; diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index d41d168c6e..7ccf28abf3 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -48,3 +48,6 @@ Fixes: - sched_setscheduler(2) allows to change the priority if the policy is equal to the value returned by sched_getscheduler(2). + +- Fix frequent page fault caused in Windows Terminal. + Addresses: https://cygwin.com/pipermail/cygwin/2024-December/256841.html From fff6372506cf162056f79038989b9eca76f7cd07 Mon Sep 17 00:00:00 2001 From: Radek Barton Date: Tue, 3 Dec 2024 16:36:45 -0500 Subject: [PATCH 31/50] Change various declarations to ANSI style to avoid problems with gcc 15 (cherry picked from commit d636b11d2e167cbcc310000ac1a977219b819fee) --- newlib/libc/posix/collate.c | 22 +-- newlib/libc/posix/collcmp.c | 6 +- newlib/libc/posix/engine.c | 82 +++++----- newlib/libc/posix/fnmatch.c | 11 +- newlib/libc/posix/regcomp.c | 265 +++++++++++++++++-------------- newlib/libc/posix/regerror.c | 7 +- newlib/libc/search/hash.c | 134 +++++++++------- newlib/libc/search/hash_bigkey.c | 102 ++++++------ newlib/libc/search/hash_buf.c | 42 ++--- newlib/libc/search/hash_func.c | 7 +- newlib/libc/search/hash_log2.c | 5 +- newlib/libc/search/hash_page.c | 127 +++++++++------ newlib/libc/search/tdestroy.c | 7 +- newlib/libc/search/twalk.c | 9 +- 14 files changed, 468 insertions(+), 358 deletions(-) diff --git a/newlib/libc/posix/collate.c b/newlib/libc/posix/collate.c index a2f62c978f..8e84895bac 100644 --- a/newlib/libc/posix/collate.c +++ b/newlib/libc/posix/collate.c @@ -58,8 +58,9 @@ struct __collate_st_chain_pri __collate_chain_pri_table[TABLE_SIZE]; void __collate_err(int ex, const char *f); int -__collate_load_tables(encoding) - char *encoding; +__collate_load_tables( + char *encoding +) { char buf[PATH_MAX]; FILE *fp; @@ -113,8 +114,9 @@ __collate_load_tables(encoding) } u_char * -__collate_substitute(s) - const u_char *s; +__collate_substitute( + const u_char *s +) { int dest_len, len, nlen; int delta = strlen((const char *) s); @@ -143,9 +145,12 @@ __collate_substitute(s) } void -__collate_lookup(t, len, prim, sec) - const u_char *t; - int *len, *prim, *sec; +__collate_lookup( + const u_char *t, + int *len, + int *prim, + int *sec +) { struct __collate_st_chain_pri *p2; @@ -165,8 +170,7 @@ __collate_lookup(t, len, prim, sec) } u_char * -__collate_strdup(s) - u_char *s; +__collate_strdup(u_char *s) { u_char *t = (u_char *) strdup((const char *) s); diff --git a/newlib/libc/posix/collcmp.c b/newlib/libc/posix/collcmp.c index 7770897619..675c4d80ae 100644 --- a/newlib/libc/posix/collcmp.c +++ b/newlib/libc/posix/collcmp.c @@ -40,8 +40,10 @@ * "[a-z]"-type ranges with national characters. */ -int __collate_range_cmp (c1, c2) - int c1, c2; +int __collate_range_cmp ( + int c1, + int c2 +) { static char s1[2], s2[2]; int ret; diff --git a/newlib/libc/posix/engine.c b/newlib/libc/posix/engine.c index c80834a0c2..cda7afa897 100644 --- a/newlib/libc/posix/engine.c +++ b/newlib/libc/posix/engine.c @@ -135,12 +135,13 @@ static char *pchar(int ch); == size_t nmatch, regmatch_t pmatch[], int eflags); */ static int /* 0 success, REG_NOMATCH failure */ -matcher(g, string, nmatch, pmatch, eflags) -struct re_guts *g; -char *string; -size_t nmatch; -regmatch_t pmatch[]; -int eflags; +matcher( + struct re_guts *g, + char *string, + size_t nmatch, + regmatch_t pmatch[], + int eflags +) { char *endp; int i; @@ -346,12 +347,13 @@ int eflags; == char *stop, sopno startst, sopno stopst); */ static char * /* == stop (success) always */ -dissect(m, start, stop, startst, stopst) -struct match *m; -char *start; -char *stop; -sopno startst; -sopno stopst; +dissect( + struct match *m, + char *start, + char *stop, + sopno startst, + sopno stopst +) { int i; sopno ss; /* start sop of current subRE */ @@ -539,13 +541,14 @@ sopno stopst; == char *stop, sopno startst, sopno stopst, sopno lev); */ static char * /* == stop (success) or NULL (failure) */ -backref(m, start, stop, startst, stopst, lev) -struct match *m; -char *start; -char *stop; -sopno startst; -sopno stopst; -sopno lev; /* PLUS nesting level */ +backref( + struct match *m, + char *start, + char *stop, + sopno startst, + sopno stopst, + sopno lev /* PLUS nesting level */ +) { int i; sopno ss; /* start sop of current subRE */ @@ -744,12 +747,13 @@ sopno lev; /* PLUS nesting level */ == char *stop, sopno startst, sopno stopst); */ static char * /* where tentative match ended, or NULL */ -fast(m, start, stop, startst, stopst) -struct match *m; -char *start; -char *stop; -sopno startst; -sopno stopst; +fast( + struct match *m, + char *start, + char *stop, + sopno startst, + sopno stopst +) { states st = m->st; states fresh = m->fresh; @@ -835,12 +839,13 @@ sopno stopst; == char *stop, sopno startst, sopno stopst); */ static char * /* where it ended */ -slow(m, start, stop, startst, stopst) -struct match *m; -char *start; -char *stop; -sopno startst; -sopno stopst; +slow( + struct match *m, + char *start, + char *stop, + sopno startst, + sopno stopst +) { states st = m->st; states empty = m->empty; @@ -931,13 +936,14 @@ sopno stopst; == #define NNONCHAR (CODEMAX-CHAR_MAX) */ static states -step(g, start, stop, bef, ch, aft) -struct re_guts *g; -sopno start; /* start state within strip */ -sopno stop; /* state after stop state within strip */ -states bef; /* states reachable before */ -int ch; /* character or NONCHAR code */ -states aft; /* states already known reachable after */ +step( + struct re_guts *g, + sopno start, /* start state within strip */ + sopno stop, /* state after stop state within strip */ + states bef, /* states reachable before */ + int ch, /* character or NONCHAR code */ + states aft /* states already known reachable after */ +) { cset *cs; sop s; diff --git a/newlib/libc/posix/fnmatch.c b/newlib/libc/posix/fnmatch.c index 1a679ab85e..1f062a54cf 100644 --- a/newlib/libc/posix/fnmatch.c +++ b/newlib/libc/posix/fnmatch.c @@ -163,11 +163,12 @@ fnmatch(pattern, string, flags) } static int -rangematch(pattern, test, flags, newp) - const char *pattern; - char test; - int flags; - char **newp; +rangematch( + const char *pattern, + char test, + int flags, + char **newp +) { int negate, ok; char c, c2; diff --git a/newlib/libc/posix/regcomp.c b/newlib/libc/posix/regcomp.c index c789746755..c839809468 100644 --- a/newlib/libc/posix/regcomp.c +++ b/newlib/libc/posix/regcomp.c @@ -303,9 +303,10 @@ int cflags; == static void p_ere(struct parse *p, int stop); */ static void -p_ere(p, stop) -struct parse *p; -int stop; /* character this ERE should end at */ +p_ere( + struct parse *p, + int stop /* character this ERE should end at */ +) { char c; sopno prevback = 0; @@ -349,8 +350,7 @@ int stop; /* character this ERE should end at */ == static void p_ere_exp(struct parse *p); */ static void -p_ere_exp(p) -struct parse *p; +p_ere_exp(struct parse *p) { char c; sopno pos; @@ -498,8 +498,7 @@ struct parse *p; == static void p_str(struct parse *p); */ static void -p_str(p) -struct parse *p; +p_str(struct parse *p) { (void)REQUIRE(MORE(), REG_EMPTY); while (MORE()) @@ -519,10 +518,11 @@ struct parse *p; * The amount of lookahead needed to avoid this kludge is excessive. */ static void -p_bre(p, end1, end2) -struct parse *p; -int end1; /* first terminating character */ -int end2; /* second terminating character */ +p_bre( + struct parse *p, + int end1, /* first terminating character */ + int end2 /* second terminating character */ +) { sopno start = HERE(); int first = 1; /* first subexpression? */ @@ -552,9 +552,10 @@ int end2; /* second terminating character */ == static int p_simp_re(struct parse *p, int starordinary); */ static int /* was the simple RE an unbackslashed $? */ -p_simp_re(p, starordinary) -struct parse *p; -int starordinary; /* is a leading * an ordinary character? */ +p_simp_re( + struct parse *p, + int starordinary /* is a leading * an ordinary character? */ +) { int c; int count; @@ -670,8 +671,7 @@ int starordinary; /* is a leading * an ordinary character? */ == static int p_count(struct parse *p); */ static int /* the value */ -p_count(p) -struct parse *p; +p_count(struct parse *p) { int count = 0; int ndigits = 0; @@ -693,8 +693,7 @@ struct parse *p; * no set operations are done. */ static void -p_bracket(p) -struct parse *p; +p_bracket(struct parse *p) { cset *cs = allocset(p); int invert = 0; @@ -767,9 +766,10 @@ struct parse *p; == static void p_b_term(struct parse *p, cset *cs); */ static void -p_b_term(p, cs) -struct parse *p; -cset *cs; +p_b_term( + struct parse *p, + cset *cs +) { char c; char start, finish; @@ -846,9 +846,10 @@ cset *cs; == static void p_b_cclass(struct parse *p, cset *cs); */ static void -p_b_cclass(p, cs) -struct parse *p; -cset *cs; +p_b_cclass( + struct parse *p, + cset *cs +) { int c; char *sp = p->next; @@ -942,9 +943,10 @@ cset *cs; * This implementation is incomplete. xxx */ static void -p_b_eclass(p, cs) -struct parse *p; -cset *cs; +p_b_eclass( + struct parse *p, + cset *cs +) { char c; @@ -957,8 +959,7 @@ cset *cs; == static char p_b_symbol(struct parse *p); */ static char /* value of symbol */ -p_b_symbol(p) -struct parse *p; +p_b_symbol(struct parse *p) { char value; @@ -977,9 +978,10 @@ struct parse *p; == static char p_b_coll_elem(struct parse *p, int endc); */ static char /* value of collating element */ -p_b_coll_elem(p, endc) -struct parse *p; -int endc; /* name ended by endc,']' */ +p_b_coll_elem( + struct parse *p, + int endc /* name ended by endc,']' */ +) { char *sp = p->next; struct cname *cp; @@ -1006,8 +1008,9 @@ int endc; /* name ended by endc,']' */ == static char othercase(int ch); */ static char /* if no counterpart, return ch */ -othercase(ch) -int ch; +othercase( + int ch +) { ch = (uch)ch; assert(isalpha(ch)); @@ -1026,9 +1029,10 @@ int ch; * Boy, is this implementation ever a kludge... */ static void -bothcases(p, ch) -struct parse *p; -int ch; +bothcases( + struct parse *p, + int ch +) { char *oldnext = p->next; char *oldend = p->end; @@ -1052,9 +1056,10 @@ int ch; == static void ordinary(struct parse *p, int ch); */ static void -ordinary(p, ch) -struct parse *p; -int ch; +ordinary( + struct parse *p, + int ch +) { cat_t *cap = p->g->categories; @@ -1074,8 +1079,9 @@ int ch; * Boy, is this implementation ever a kludge... */ static void -nonnewline(p) -struct parse *p; +nonnewline( + struct parse *p +) { char *oldnext = p->next; char *oldend = p->end; @@ -1098,11 +1104,12 @@ struct parse *p; == static void repeat(struct parse *p, sopno start, int from, int to); */ static void -repeat(p, start, from, to) -struct parse *p; -sopno start; /* operand from here to end of strip */ -int from; /* repeated from this number */ -int to; /* to this number of times (maybe INFINITY) */ +repeat( + struct parse *p, + sopno start, /* operand from here to end of strip */ + int from, /* repeated from this number */ + int to /* to this number of times (maybe INFINITY) */ +) { sopno finish = HERE(); # define N 2 @@ -1170,9 +1177,10 @@ int to; /* to this number of times (maybe INFINITY) */ == static int seterr(struct parse *p, int e); */ static int /* useless but makes type checking happy */ -seterr(p, e) -struct parse *p; -int e; +seterr( + struct parse *p, + int e +) { if (p->error == 0) /* keep earliest error condition */ p->error = e; @@ -1186,8 +1194,7 @@ int e; == static cset *allocset(struct parse *p); */ static cset * -allocset(p) -struct parse *p; +allocset(struct parse *p) { int no = p->g->ncsets++; size_t nc; @@ -1241,9 +1248,10 @@ struct parse *p; == static void freeset(struct parse *p, cset *cs); */ static void -freeset(p, cs) -struct parse *p; -cset *cs; +freeset( + struct parse *p, + cset *cs +) { int i; cset *top = &p->g->sets[p->g->ncsets]; @@ -1266,9 +1274,10 @@ cset *cs; * the same value! */ static int /* set number */ -freezeset(p, cs) -struct parse *p; -cset *cs; +freezeset( + struct parse *p, + cset *cs +) { short h = cs->hash; int i; @@ -1300,9 +1309,10 @@ cset *cs; == static int firstch(struct parse *p, cset *cs); */ static int /* character; there is no "none" value */ -firstch(p, cs) -struct parse *p; -cset *cs; +firstch( + struct parse *p, + cset *cs +) { int i; size_t css = (size_t)p->g->csetsize; @@ -1319,9 +1329,10 @@ cset *cs; == static int nch(struct parse *p, cset *cs); */ static int -nch(p, cs) -struct parse *p; -cset *cs; +nch( + struct parse *p, + cset *cs +) { int i; size_t css = (size_t)p->g->csetsize; @@ -1428,9 +1439,10 @@ char *cp; * is deferred. */ static void -mcinvert(p, cs) -struct parse *p; -cset *cs; +mcinvert( + struct parse *p, + cset *cs +) { assert(cs->multis == NULL); /* xxx */ } @@ -1443,9 +1455,10 @@ cset *cs; * is deferred. */ static void -mccase(p, cs) -struct parse *p; -cset *cs; +mccase( + struct parse *p, + cset *cs +) { assert(cs->multis == NULL); /* xxx */ } @@ -1455,9 +1468,10 @@ cset *cs; == static int isinsets(struct re_guts *g, int c); */ static int /* predicate */ -isinsets(g, c) -struct re_guts *g; -int c; +isinsets( + struct re_guts *g, + int c +) { uch *col; int i; @@ -1475,10 +1489,11 @@ int c; == static int samesets(struct re_guts *g, int c1, int c2); */ static int /* predicate */ -samesets(g, c1, c2) -struct re_guts *g; -int c1; -int c2; +samesets( + struct re_guts *g, + int c1, + int c2 +) { uch *col; int i; @@ -1497,9 +1512,10 @@ int c2; == static void categorize(struct parse *p, struct re_guts *g); */ static void -categorize(p, g) -struct parse *p; -struct re_guts *g; +categorize( + struct parse *p, + struct re_guts *g +) { cat_t *cats = g->categories; int c; @@ -1525,10 +1541,11 @@ struct re_guts *g; == static sopno dupl(struct parse *p, sopno start, sopno finish); */ static sopno /* start of duplicate */ -dupl(p, start, finish) -struct parse *p; -sopno start; /* from here */ -sopno finish; /* to this less one */ +dupl( + struct parse *p, + sopno start, /* from here */ + sopno finish /* to this less one */ +) { sopno ret = HERE(); sopno len = finish - start; @@ -1553,10 +1570,11 @@ sopno finish; /* to this less one */ * some changes to the data structures. Maybe later. */ static void -doemit(p, op, opnd) -struct parse *p; -sop op; -size_t opnd; +doemit( + struct parse *p, + sop op, + size_t opnd +) { /* avoid making error situations worse */ if (p->error != 0) @@ -1579,11 +1597,12 @@ size_t opnd; == static void doinsert(struct parse *p, sop op, size_t opnd, sopno pos); */ static void -doinsert(p, op, opnd, pos) -struct parse *p; -sop op; -size_t opnd; -sopno pos; +doinsert( + struct parse *p, + sop op, + size_t opnd, + sopno pos +) { sopno sn; sop s; @@ -1619,10 +1638,11 @@ sopno pos; == static void dofwd(struct parse *p, sopno pos, sop value); */ static void -dofwd(p, pos, value) -struct parse *p; -sopno pos; -sop value; +dofwd( + struct parse *p, + sopno pos, + sop value +) { /* avoid making error situations worse */ if (p->error != 0) @@ -1637,9 +1657,10 @@ sop value; == static void enlarge(struct parse *p, sopno size); */ static void -enlarge(p, size) -struct parse *p; -sopno size; +enlarge( + struct parse *p, + sopno size +) { sop *sp; @@ -1660,9 +1681,10 @@ sopno size; == static void stripsnug(struct parse *p, struct re_guts *g); */ static void -stripsnug(p, g) -struct parse *p; -struct re_guts *g; +stripsnug( + struct parse *p, + struct re_guts *g +) { g->nstates = p->slen; g->strip = (sop *)realloc((char *)p->strip, p->slen * sizeof(sop)); @@ -1683,9 +1705,10 @@ struct re_guts *g; * Note that must and mlen got initialized during setup. */ static void -findmust(p, g) -struct parse *p; -struct re_guts *g; +findmust( + struct parse *p, + struct re_guts *g +) { sop *scan; sop *start = NULL; @@ -1852,10 +1875,11 @@ struct re_guts *g; * re paths. */ static int -altoffset(scan, offset, mccs) -sop *scan; -int offset; -int mccs; +altoffset( + sop *scan, + int offset, + int mccs +) { int largest; int try; @@ -1932,9 +1956,10 @@ int mccs; * the value of the character from the text that was mismatched. */ static void -computejumps(p, g) -struct parse *p; -struct re_guts *g; +computejumps( + struct parse *p, + struct re_guts *g +) { int ch; int mindex; @@ -1978,9 +2003,10 @@ struct re_guts *g; * the search algorithm works. */ static void -computematchjumps(p, g) -struct parse *p; -struct re_guts *g; +computematchjumps( + struct parse *p, + struct re_guts *g +) { int mindex; /* General "must" iterator */ int suffix; /* Keeps track of matching suffix */ @@ -2056,9 +2082,10 @@ struct re_guts *g; == static sopno pluscount(struct parse *p, struct re_guts *g); */ static sopno /* nesting depth */ -pluscount(p, g) -struct parse *p; -struct re_guts *g; +pluscount( + struct parse *p, + struct re_guts *g +) { sop *scan; sop s; diff --git a/newlib/libc/posix/regerror.c b/newlib/libc/posix/regerror.c index a48d37c729..1b07b636c7 100644 --- a/newlib/libc/posix/regerror.c +++ b/newlib/libc/posix/regerror.c @@ -160,9 +160,10 @@ size_t errbuf_size; == static char *regatoi(const regex_t *preg, char *localbuf); */ static char * -regatoi(preg, localbuf) -const regex_t *preg; -char *localbuf; +regatoi( + const regex_t *preg, + char *localbuf +) { struct rerr *r; diff --git a/newlib/libc/search/hash.c b/newlib/libc/search/hash.c index 33ff275d94..f242337f5b 100644 --- a/newlib/libc/search/hash.c +++ b/newlib/libc/search/hash.c @@ -276,8 +276,9 @@ __hash_open (const char *file, } static int -hash_close(dbp) - DB *dbp; +hash_close( + DB *dbp +) { HTAB *hashp; int retval; @@ -292,8 +293,9 @@ hash_close(dbp) } static int -hash_fd(dbp) - const DB *dbp; +hash_fd( + const DB *dbp +) { HTAB *hashp; @@ -310,10 +312,11 @@ hash_fd(dbp) /************************** LOCAL CREATION ROUTINES **********************/ static HTAB * -init_hash(hashp, file, info) - HTAB *hashp; - const char *file; - const HASHINFO *info; +init_hash( + HTAB *hashp, + const char *file, + const HASHINFO *info +) { #ifdef __USE_INTERNAL_STAT64 struct stat64 statbuf; @@ -385,9 +388,10 @@ init_hash(hashp, file, info) * Returns 0 on No Error */ static int -init_htab(hashp, nelem) - HTAB *hashp; - int nelem; +init_htab( + HTAB *hashp, + int nelem +) { int nbuckets, nsegs; int l2; @@ -431,8 +435,9 @@ init_htab(hashp, nelem) * structure, freeing all allocated space. */ static int -hdestroy(hashp) - HTAB *hashp; +hdestroy( + HTAB *hashp +) { int i, save_errno; @@ -491,9 +496,10 @@ hdestroy(hashp) * -1 ERROR */ static int -hash_sync(dbp, flags) - const DB *dbp; - u_int flags; +hash_sync( + const DB *dbp, + u_int flags +) { HTAB *hashp; @@ -520,8 +526,9 @@ hash_sync(dbp, flags) * -1 indicates that errno should be set */ static int -flush_meta(hashp) - HTAB *hashp; +flush_meta( + HTAB *hashp +) { HASHHDR *whdrp; #if (BYTE_ORDER == LITTLE_ENDIAN) @@ -568,11 +575,12 @@ flush_meta(hashp) * -1 to indicate an internal ERROR (i.e. out of memory, etc) */ static int -hash_get(dbp, key, data, flag) - const DB *dbp; - const DBT *key; - DBT *data; - u_int flag; +hash_get( + const DB *dbp, + const DBT *key, + DBT *data, + u_int flag +) { HTAB *hashp; @@ -585,11 +593,12 @@ hash_get(dbp, key, data, flag) } static int -hash_put(dbp, key, data, flag) - const DB *dbp; - DBT *key; - const DBT *data; - u_int flag; +hash_put( + const DB *dbp, + DBT *key, + const DBT *data, + u_int flag +) { HTAB *hashp; @@ -608,10 +617,11 @@ hash_put(dbp, key, data, flag) } static int -hash_delete(dbp, key, flag) - const DB *dbp; - const DBT *key; - u_int flag; /* Ignored */ +hash_delete( + const DB *dbp, + const DBT *key, + u_int flag /* Ignored */ +) { HTAB *hashp; @@ -631,10 +641,12 @@ hash_delete(dbp, key, flag) * Assume that hashp has been set in wrapper routine. */ static int -hash_access(hashp, action, key, val) - HTAB *hashp; - ACTION action; - DBT *key, *val; +hash_access( + HTAB *hashp, + ACTION action, + DBT *key, + DBT *val +) { BUFHEAD *rbufp; BUFHEAD *bufp, *save_bufp; @@ -760,10 +772,12 @@ hash_access(hashp, action, key, val) } static int -hash_seq(dbp, key, data, flag) - const DB *dbp; - DBT *key, *data; - u_int flag; +hash_seq( + const DB *dbp, + DBT *key, + DBT *data, + u_int flag +) { __uint32_t bucket; BUFHEAD *bufp; @@ -850,8 +864,9 @@ hash_seq(dbp, key, data, flag) * -1 ==> Error */ extern int -__expand_table(hashp) - HTAB *hashp; +__expand_table( + HTAB *hashp +) { __uint32_t old_bucket, new_bucket; int dirsize, new_segnum, spare_ndx; @@ -905,9 +920,11 @@ __expand_table(hashp) * fails, then this routine can go away. */ static void * -hash_realloc(p_ptr, oldsize, newsize) - SEGMENT **p_ptr; - int oldsize, newsize; +hash_realloc( + SEGMENT **p_ptr, + int oldsize, + int newsize +) { void *p; @@ -921,10 +938,11 @@ hash_realloc(p_ptr, oldsize, newsize) } extern __uint32_t -__call_hash(hashp, k, len) - HTAB *hashp; - char *k; - int len; +__call_hash( + HTAB *hashp, + char *k, + int len +) { int n, bucket; @@ -941,9 +959,10 @@ __call_hash(hashp, k, len) * Returns 0 on success */ static int -alloc_segs(hashp, nsegs) - HTAB *hashp; - int nsegs; +alloc_segs( + HTAB *hashp, + int nsegs +) { int i; SEGMENT store; @@ -975,8 +994,10 @@ alloc_segs(hashp, nsegs) * Hashp->hdr needs to be byteswapped. */ static void -swap_header_copy(srcp, destp) - HASHHDR *srcp, *destp; +swap_header_copy( + HASHHDR *srcp, + HASHHDR *destp +) { int i; @@ -1004,8 +1025,9 @@ swap_header_copy(srcp, destp) } static void -swap_header(hashp) - HTAB *hashp; +swap_header( + HTAB *hashp +) { HASHHDR *hdrp; int i; diff --git a/newlib/libc/search/hash_bigkey.c b/newlib/libc/search/hash_bigkey.c index e110e46945..29a14502a7 100644 --- a/newlib/libc/search/hash_bigkey.c +++ b/newlib/libc/search/hash_bigkey.c @@ -83,10 +83,12 @@ static int collect_data(HTAB *, BUFHEAD *, int, int); *-1 ==> ERROR */ extern int -__big_insert(hashp, bufp, key, val) - HTAB *hashp; - BUFHEAD *bufp; - const DBT *key, *val; +__big_insert( + HTAB *hashp, + BUFHEAD *bufp, + const DBT *key, + const DBT *val +) { __uint16_t *p; int key_size, n, val_size; @@ -183,9 +185,10 @@ __big_insert(hashp, bufp, key, val) *-1 => ERROR */ extern int -__big_delete(hashp, bufp) - HTAB *hashp; - BUFHEAD *bufp; +__big_delete( + HTAB *hashp, + BUFHEAD *bufp +) { BUFHEAD *last_bfp, *rbufp; __uint16_t *bp, pageno; @@ -262,12 +265,13 @@ __big_delete(hashp, bufp) * -3 error */ extern int -__find_bigpair(hashp, bufp, ndx, key, size) - HTAB *hashp; - BUFHEAD *bufp; - int ndx; - char *key; - int size; +__find_bigpair( + HTAB *hashp, + BUFHEAD *bufp, + int ndx, + char *key, + int size +) { __uint16_t *bp; char *p; @@ -314,9 +318,10 @@ __find_bigpair(hashp, bufp, ndx, key, size) * bucket) */ extern __uint16_t -__find_last_page(hashp, bpp) - HTAB *hashp; - BUFHEAD **bpp; +__find_last_page( + HTAB *hashp, + BUFHEAD **bpp +) { BUFHEAD *bufp; __uint16_t *bp, pageno; @@ -355,12 +360,13 @@ __find_last_page(hashp, bpp) * index (index should always be 1). */ extern int -__big_return(hashp, bufp, ndx, val, set_current) - HTAB *hashp; - BUFHEAD *bufp; - int ndx; - DBT *val; - int set_current; +__big_return( + HTAB *hashp, + BUFHEAD *bufp, + int ndx, + DBT *val, + int set_current +) { BUFHEAD *save_p; __uint16_t *bp, len, off, save_addr; @@ -446,10 +452,12 @@ __big_return(hashp, bufp, ndx, val, set_current) * allocate a buffer and copy the data as you recurse up. */ static int -collect_data(hashp, bufp, len, set) - HTAB *hashp; - BUFHEAD *bufp; - int len, set; +collect_data( + HTAB *hashp, + BUFHEAD *bufp, + int len, + int set +) { __uint16_t *bp; char *p; @@ -502,11 +510,13 @@ collect_data(hashp, bufp, len, set) * Fill in the key and data for this big pair. */ extern int -__big_keydata(hashp, bufp, key, val, set) - HTAB *hashp; - BUFHEAD *bufp; - DBT *key, *val; - int set; +__big_keydata( + HTAB *hashp, + BUFHEAD *bufp, + DBT *key, + DBT *val, + int set +) { key->size = collect_key(hashp, bufp, 0, val, set); if (key->size == -1) @@ -520,12 +530,13 @@ __big_keydata(hashp, bufp, key, val, set) * collect the data, allocate a buffer and copy the key as you recurse up. */ static int -collect_key(hashp, bufp, len, val, set) - HTAB *hashp; - BUFHEAD *bufp; - int len; - DBT *val; - int set; +collect_key( + HTAB *hashp, + BUFHEAD *bufp, + int len, + DBT *val, + int set +) { BUFHEAD *xbp; char *p; @@ -565,15 +576,16 @@ collect_key(hashp, bufp, len, val, set) * -1 => error */ extern int -__big_split(hashp, op, np, big_keyp, addr, obucket, ret) - HTAB *hashp; - BUFHEAD *op; /* Pointer to where to put keys that go in old bucket */ - BUFHEAD *np; /* Pointer to new bucket page */ +__big_split( + HTAB *hashp, + BUFHEAD *op, /* Pointer to where to put keys that go in old bucket */ + BUFHEAD *np, /* Pointer to new bucket page */ /* Pointer to first page containing the big key/data */ - BUFHEAD *big_keyp; - int addr; /* Address of big_keyp */ - __uint32_t obucket;/* Old Bucket */ - SPLIT_RETURN *ret; + BUFHEAD *big_keyp, + int addr, /* Address of big_keyp */ + __uint32_t obucket,/* Old Bucket */ + SPLIT_RETURN *ret +) { BUFHEAD *tmpp; __uint16_t *tp; diff --git a/newlib/libc/search/hash_buf.c b/newlib/libc/search/hash_buf.c index 2b921681a7..7f8e90b679 100644 --- a/newlib/libc/search/hash_buf.c +++ b/newlib/libc/search/hash_buf.c @@ -107,11 +107,12 @@ static BUFHEAD *newbuf(HTAB *, __uint32_t, BUFHEAD *); * address you are seeking. */ extern BUFHEAD * -__get_buf(hashp, addr, prev_bp, newpage) - HTAB *hashp; - __uint32_t addr; - BUFHEAD *prev_bp; - int newpage; /* If prev_bp set, indicates a new overflow page. */ +__get_buf( + HTAB *hashp, + __uint32_t addr, + BUFHEAD *prev_bp, + int newpage /* If prev_bp set, indicates a new overflow page. */ +) { BUFHEAD *bp; __uint32_t is_disk_mask; @@ -162,10 +163,11 @@ __get_buf(hashp, addr, prev_bp, newpage) * If newbuf finds an error (returning NULL), it also sets errno. */ static BUFHEAD * -newbuf(hashp, addr, prev_bp) - HTAB *hashp; - __uint32_t addr; - BUFHEAD *prev_bp; +newbuf( + HTAB *hashp, + __uint32_t addr, + BUFHEAD *prev_bp +) { BUFHEAD *bp; /* The buffer we're going to use */ BUFHEAD *xbp; /* Temp pointer */ @@ -292,9 +294,10 @@ newbuf(hashp, addr, prev_bp) } extern void -__buf_init(hashp, nbytes) - HTAB *hashp; - int nbytes; +__buf_init( + HTAB *hashp, + int nbytes +) { BUFHEAD *bfp; int npages; @@ -317,9 +320,11 @@ __buf_init(hashp, nbytes) } extern int -__buf_free(hashp, do_free, to_disk) - HTAB *hashp; - int do_free, to_disk; +__buf_free( + HTAB *hashp, + int do_free, + int to_disk +) { BUFHEAD *bp; @@ -348,9 +353,10 @@ __buf_free(hashp, do_free, to_disk) } extern void -__reclaim_buf(hashp, bp) - HTAB *hashp; - BUFHEAD *bp; +__reclaim_buf( + HTAB *hashp, + BUFHEAD *bp +) { bp->ovfl = 0; bp->addr = 0; diff --git a/newlib/libc/search/hash_func.c b/newlib/libc/search/hash_func.c index 30263d0f63..ad8dd666d6 100644 --- a/newlib/libc/search/hash_func.c +++ b/newlib/libc/search/hash_func.c @@ -167,9 +167,10 @@ hash3(keyarg, len) /* Hash function from Chris Torek. */ static __uint32_t -hash4(keyarg, len) - const void *keyarg; - size_t len; +hash4( + const void *keyarg, + size_t len +) { const u_char *key; size_t loop; diff --git a/newlib/libc/search/hash_log2.c b/newlib/libc/search/hash_log2.c index 622c228474..0bc766af55 100644 --- a/newlib/libc/search/hash_log2.c +++ b/newlib/libc/search/hash_log2.c @@ -40,8 +40,9 @@ static char sccsid[] = "@(#)hash_log2.c 8.2 (Berkeley) 5/31/94"; #include "db_local.h" __uint32_t -__log2(num) - __uint32_t num; +__log2( + __uint32_t num +) { __uint32_t i, limit; diff --git a/newlib/libc/search/hash_page.c b/newlib/libc/search/hash_page.c index 9d15b0cb70..c073f49dfc 100644 --- a/newlib/libc/search/hash_page.c +++ b/newlib/libc/search/hash_page.c @@ -91,9 +91,11 @@ static int ugly_split * stuff on. */ static void -putpair(p, key, val) - char *p; - const DBT *key, *val; +putpair( + char *p, + const DBT *key, + const DBT *val +) { __uint16_t *bp, n, off; @@ -123,10 +125,11 @@ putpair(p, key, val) * -1 error */ extern int -__delpair(hashp, bufp, ndx) - HTAB *hashp; - BUFHEAD *bufp; - int ndx; +__delpair( + HTAB *hashp, + BUFHEAD *bufp, + int ndx +) { __uint16_t *bp, newoff; int n; @@ -176,9 +179,11 @@ __delpair(hashp, bufp, ndx) * -1 ==> Error */ extern int -__split_page(hashp, obucket, nbucket) - HTAB *hashp; - __uint32_t obucket, nbucket; +__split_page( + HTAB *hashp, + __uint32_t obucket, + __uint32_t nbucket +) { BUFHEAD *new_bufp, *old_bufp; __uint16_t *ino; @@ -272,12 +277,14 @@ __split_page(hashp, obucket, nbucket) * -1 ==> failure */ static int -ugly_split(hashp, obucket, old_bufp, new_bufp, copyto, moved) - HTAB *hashp; - __uint32_t obucket; /* Same as __split_page. */ - BUFHEAD *old_bufp, *new_bufp; - int copyto; /* First byte on page which contains key/data values. */ - int moved; /* Number of pairs moved to new page. */ +ugly_split( + HTAB *hashp, + __uint32_t obucket, /* Same as __split_page. */ + BUFHEAD *old_bufp, + BUFHEAD *new_bufp, + int copyto, /* First byte on page which contains key/data values. */ + int moved /* Number of pairs moved to new page. */ +) { BUFHEAD *bufp; /* Buffer header for ino */ __uint16_t *ino; /* Page keys come off of */ @@ -393,10 +400,12 @@ ugly_split(hashp, obucket, old_bufp, new_bufp, copyto, moved) * 1 ==> failure */ extern int -__addel(hashp, bufp, key, val) - HTAB *hashp; - BUFHEAD *bufp; - const DBT *key, *val; +__addel( + HTAB *hashp, + BUFHEAD *bufp, + const DBT *key, + const DBT *val +) { __uint16_t *bp, *sop; int do_expand; @@ -460,9 +469,10 @@ __addel(hashp, bufp, key, val) * NULL on error */ extern BUFHEAD * -__add_ovflpage(hashp, bufp) - HTAB *hashp; - BUFHEAD *bufp; +__add_ovflpage( + HTAB *hashp, + BUFHEAD *bufp +) { __uint16_t *sp; __uint16_t ndx, ovfl_num; @@ -513,11 +523,14 @@ __add_ovflpage(hashp, bufp) * -1 indicates FAILURE */ extern int -__get_page(hashp, p, bucket, is_bucket, is_disk, is_bitmap) - HTAB *hashp; - char *p; - __uint32_t bucket; - int is_bucket, is_disk, is_bitmap; +__get_page( + HTAB *hashp, + char *p, + __uint32_t bucket, + int is_bucket, + int is_disk, + int is_bitmap +) { int fd, page, size; int rsize; @@ -573,11 +586,13 @@ __get_page(hashp, p, bucket, is_bucket, is_disk, is_bitmap) * -1 ==>failure */ extern int -__put_page(hashp, p, bucket, is_bucket, is_bitmap) - HTAB *hashp; - char *p; - __uint32_t bucket; - int is_bucket, is_bitmap; +__put_page( + HTAB *hashp, + char *p, + __uint32_t bucket, + int is_bucket, + int is_bitmap +) { int fd, page, size; int wsize; @@ -622,9 +637,12 @@ __put_page(hashp, p, bucket, is_bucket, is_bitmap) * once they are read in. */ extern int -__ibitmap(hashp, pnum, nbits, ndx) - HTAB *hashp; - int pnum, nbits, ndx; +__ibitmap( + HTAB *hashp, + int pnum, + int nbits, + int ndx +) { __uint32_t *ip; int clearbytes, clearints; @@ -645,8 +663,9 @@ __ibitmap(hashp, pnum, nbits, ndx) } static __uint32_t -first_free(map) - __uint32_t map; +first_free( + __uint32_t map +) { __uint32_t i, mask; @@ -660,8 +679,9 @@ first_free(map) } static __uint16_t -overflow_page(hashp) - HTAB *hashp; +overflow_page( + HTAB *hashp +) { __uint32_t *freep = NULL; int max_free, offset, splitnum; @@ -808,9 +828,10 @@ overflow_page(hashp) * Mark this overflow page as free. */ extern void -__free_ovflpage(hashp, obufp) - HTAB *hashp; - BUFHEAD *obufp; +__free_ovflpage( + HTAB *hashp, + BUFHEAD *obufp +) { __uint16_t addr; __uint32_t *freep; @@ -854,8 +875,9 @@ __free_ovflpage(hashp, obufp) * -1 failure */ static int -open_temp(hashp) - HTAB *hashp; +open_temp( + HTAB *hashp +) { sigset_t set, oset; static char namestr[] = "_hashXXXXXX"; @@ -878,9 +900,11 @@ open_temp(hashp) * an overflow pair, so we need to shift things. */ static void -squeeze_key(sp, key, val) - __uint16_t *sp; - const DBT *key, *val; +squeeze_key( + __uint16_t *sp, + const DBT *key, + const DBT *val +) { char *p; __uint16_t free_space, n, off, pageno; @@ -905,9 +929,10 @@ squeeze_key(sp, key, val) } static __uint32_t * -fetch_bitmap(hashp, ndx) - HTAB *hashp; - int ndx; +fetch_bitmap( + HTAB *hashp, + int ndx +) { if (ndx >= hashp->nmaps) return (NULL); diff --git a/newlib/libc/search/tdestroy.c b/newlib/libc/search/tdestroy.c index 04c6b70520..23c4b0e70f 100644 --- a/newlib/libc/search/tdestroy.c +++ b/newlib/libc/search/tdestroy.c @@ -26,9 +26,10 @@ __RCSID("$NetBSD: tdelete.c,v 1.2 1999/09/16 11:45:37 lukem Exp $"); /* Walk the nodes of a tree */ static void -trecurse(root, free_action) - node_t *root; /* Root of the tree to be walked */ - void (*free_action)(void *); +trecurse( + node_t *root, /* Root of the tree to be walked */ + void (*free_action)(void *) +) { if (root->llink != NULL) trecurse(root->llink, free_action); diff --git a/newlib/libc/search/twalk.c b/newlib/libc/search/twalk.c index 02ef52242f..7aec6e4dd2 100644 --- a/newlib/libc/search/twalk.c +++ b/newlib/libc/search/twalk.c @@ -28,10 +28,11 @@ static void trecurse(const node_t *, /* Walk the nodes of a tree */ static void -trecurse(root, action, level) - const node_t *root; /* Root of the tree to be walked */ - void (*action)(const void *, VISIT, int); - int level; +trecurse( + const node_t *root, /* Root of the tree to be walked */ + void (*action)(const void *, VISIT, int), + int level +) { if (root->llink == NULL && root->rlink == NULL) From c8e978a3e50e6bd88110eee20188612e3e9e4b3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radek=20Barto=C5=88?= Date: Wed, 4 Dec 2024 12:33:23 +0100 Subject: [PATCH 32/50] Cygwin: Fix compatibility with GCC 15 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Radek Bartoň (cherry picked from commit c79954439e6d91dc6f421a761953f0d935c5f3d5) --- winsup/cygwin/libc/fts.c | 3 +- winsup/cygwin/libc/inet_network.c | 3 +- winsup/testsuite/libltp/include/test.h | 2 +- winsup/testsuite/libltp/include/usctest.h | 2 +- winsup/testsuite/libltp/include/write_log.h | 2 +- winsup/testsuite/libltp/lib/dataascii.c | 24 +++++----- winsup/testsuite/libltp/lib/databin.c | 24 +++++----- winsup/testsuite/libltp/lib/datapid.c | 24 +++++----- winsup/testsuite/libltp/lib/forker.c | 16 +++---- winsup/testsuite/libltp/lib/parse_opts.c | 20 ++++---- winsup/testsuite/libltp/lib/pattern.c | 26 +++++----- winsup/testsuite/libltp/lib/search_path.c | 11 +++-- winsup/testsuite/libltp/lib/str_to_bytes.c | 9 ++-- .../testsuite/libltp/lib/string_to_tokens.c | 2 +- winsup/testsuite/libltp/lib/tst_res.c | 2 - winsup/testsuite/libltp/lib/tst_sig.c | 4 +- winsup/testsuite/libltp/lib/write_log.c | 48 ++++++++++--------- 17 files changed, 116 insertions(+), 106 deletions(-) diff --git a/winsup/cygwin/libc/fts.c b/winsup/cygwin/libc/fts.c index 1826d22137..6f060e54e3 100644 --- a/winsup/cygwin/libc/fts.c +++ b/winsup/cygwin/libc/fts.c @@ -1111,8 +1111,7 @@ fts_padjust(FTS *sp, FTSENT *head) } static size_t -fts_maxarglen(argv) - char * const *argv; +fts_maxarglen(char * const *argv) { size_t len, max; diff --git a/winsup/cygwin/libc/inet_network.c b/winsup/cygwin/libc/inet_network.c index 43a394cf45..17b61f7aab 100644 --- a/winsup/cygwin/libc/inet_network.c +++ b/winsup/cygwin/libc/inet_network.c @@ -56,8 +56,7 @@ __FBSDID("$FreeBSD$"); * network numbers. */ in_addr_t -cygwin_inet_network(cp) - const char *cp; +cygwin_inet_network(const char *cp) { in_addr_t val, base, n; char c; diff --git a/winsup/testsuite/libltp/include/test.h b/winsup/testsuite/libltp/include/test.h index 757f3b8a1d..af7c3c0c88 100644 --- a/winsup/testsuite/libltp/include/test.h +++ b/winsup/testsuite/libltp/include/test.h @@ -225,7 +225,7 @@ extern void tt_exit(); extern int t_environ(); extern void t_breakum(char *tcid, int total, int typ, char *msg, void (*fnc)()); -extern void tst_sig(int fork_flag, void (*handler)(), void (*cleanup)()); +extern void tst_sig(int fork_flag, void (*handler)(int), void (*cleanup)()); extern void tst_tmpdir(); extern void tst_rmdir(); diff --git a/winsup/testsuite/libltp/include/usctest.h b/winsup/testsuite/libltp/include/usctest.h index 637635a251..08db49551d 100644 --- a/winsup/testsuite/libltp/include/usctest.h +++ b/winsup/testsuite/libltp/include/usctest.h @@ -198,7 +198,7 @@ struct tblock { * in the macros that follow. ***********************************************************************/ extern struct tblock tblock; -extern void STD_go(); +extern void STD_go(int); extern int (*_TMP_FUNC)(void); extern void STD_opts_help(); diff --git a/winsup/testsuite/libltp/include/write_log.h b/winsup/testsuite/libltp/include/write_log.h index 784d5b3ebb..505d2c08a8 100644 --- a/winsup/testsuite/libltp/include/write_log.h +++ b/winsup/testsuite/libltp/include/write_log.h @@ -154,7 +154,7 @@ extern int wlog_close(struct wlog_file *wfile); extern int wlog_record_write(struct wlog_file *wfile, struct wlog_rec *wrec, long offset); extern int wlog_scan_backward(struct wlog_file *wfile, int nrecs, - int (*func)(struct wlog_rec *rec), + int (*func)(struct wlog_rec *rec, long), long data); #else int wlog_open(); diff --git a/winsup/testsuite/libltp/lib/dataascii.c b/winsup/testsuite/libltp/lib/dataascii.c index 5bc2018527..41ed440c01 100644 --- a/winsup/testsuite/libltp/lib/dataascii.c +++ b/winsup/testsuite/libltp/lib/dataascii.c @@ -43,11 +43,12 @@ static char Errmsg[80]; int -dataasciigen(listofchars, buffer, bsize, offset) -char *listofchars; /* a null terminated list of characters */ -char *buffer; -int bsize; -int offset; +dataasciigen( + char *listofchars, /* a null terminated list of characters */ + char *buffer, + int bsize, + int offset +) { int cnt; int total; @@ -78,12 +79,13 @@ int offset; } /* end of dataasciigen */ int -dataasciichk(listofchars, buffer, bsize, offset, errmsg) -char *listofchars; /* a null terminated list of characters */ -char *buffer; -int bsize; -int offset; -char **errmsg; +dataasciichk( + char *listofchars, /* a null terminated list of characters */ + char *buffer, + int bsize, + int offset, + char **errmsg +) { int cnt; int total; diff --git a/winsup/testsuite/libltp/lib/databin.c b/winsup/testsuite/libltp/lib/databin.c index e43fef4e46..6cf27f77c2 100644 --- a/winsup/testsuite/libltp/lib/databin.c +++ b/winsup/testsuite/libltp/lib/databin.c @@ -42,11 +42,12 @@ static char Errmsg[80]; void -databingen (mode, buffer, bsize, offset) -int mode; /* either a, c, r, o, z or C */ -unsigned char *buffer; /* buffer pointer */ -int bsize; /* size of buffer */ -int offset; /* offset into the file where buffer starts */ +databingen ( + int mode, /* either a, c, r, o, z or C */ + unsigned char *buffer, /* buffer pointer */ + int bsize, /* size of buffer */ + int offset /* offset into the file where buffer starts */ +) { int ind; @@ -89,12 +90,13 @@ int ind; * < 0 : no error ***********************************************************************/ int -databinchk(mode, buffer, bsize, offset, errmsg) -int mode; /* either a, c, r, z, o, or C */ -unsigned char *buffer; /* buffer pointer */ -int bsize; /* size of buffer */ -int offset; /* offset into the file where buffer starts */ -char **errmsg; +databinchk( + int mode, /* either a, c, r, z, o, or C */ + unsigned char *buffer, /* buffer pointer */ + int bsize, /* size of buffer */ + int offset, /* offset into the file where buffer starts */ + char **errmsg +) { int cnt; unsigned char *chr; diff --git a/winsup/testsuite/libltp/lib/datapid.c b/winsup/testsuite/libltp/lib/datapid.c index 9414eae901..ca091311bf 100644 --- a/winsup/testsuite/libltp/lib/datapid.c +++ b/winsup/testsuite/libltp/lib/datapid.c @@ -83,11 +83,12 @@ static char Errmsg[80]; * Thus, offset 8 is in middle of word 1 ***********************************************************************/ int -datapidgen(pid, buffer, bsize, offset) -int pid; -char *buffer; -int bsize; -int offset; +datapidgen( + int pid, + char *buffer, + int bsize, + int offset +) { #if CRAY @@ -178,12 +179,13 @@ printf("partial at end\n"); * ***********************************************************************/ int -datapidchk(pid, buffer, bsize, offset, errmsg) -int pid; -char *buffer; -int bsize; -int offset; -char **errmsg; +datapidchk( + int pid, + char *buffer, + int bsize, + int offset, + char **errmsg +) { #if CRAY diff --git a/winsup/testsuite/libltp/lib/forker.c b/winsup/testsuite/libltp/lib/forker.c index 99bc585501..65f1036a3e 100644 --- a/winsup/testsuite/libltp/lib/forker.c +++ b/winsup/testsuite/libltp/lib/forker.c @@ -133,8 +133,7 @@ int Forker_npids=0; /* number of entries in Forker_pids */ * !0 : if fork failed, the return value will be the errno. ***********************************************************************/ int -background(prefix) -char *prefix; +background(char *prefix) { switch (fork()) { case -1: @@ -159,12 +158,13 @@ char *prefix; * ***********************************************************************/ int -forker(ncopies, mode, prefix) -int ncopies; -int mode; /* 0 - all childern of parent, 1 - only 1 direct child */ -char *prefix; /* if ! NULL, an message will be printed to stderr */ - /* if fork fails. The prefix (program name) will */ - /* preceed the message */ +forker( + int ncopies, + int mode, /* 0 - all childern of parent, 1 - only 1 direct child */ + char *prefix /* if ! NULL, an message will be printed to stderr */ + /* if fork fails. The prefix (program name) will */ + /* preceed the message */ +) { int cnt; int pid; diff --git a/winsup/testsuite/libltp/lib/parse_opts.c b/winsup/testsuite/libltp/lib/parse_opts.c index 1f41bfdd26..4a3c330875 100644 --- a/winsup/testsuite/libltp/lib/parse_opts.c +++ b/winsup/testsuite/libltp/lib/parse_opts.c @@ -198,7 +198,11 @@ int STD_ERRNO_LIST[USC_MAX_ERRNO]; #define STRLEN 2048 static char Mesg2[STRLEN]; /* holds possible return string */ -static void usc_recressive_func(); +static void usc_recressive_func( + int cnt, + int max, + struct usc_bigstack_t **bstack +); /* * Define bits for options that might have env variable default @@ -633,7 +637,7 @@ usc_global_setup_hook() if ( STD_PAUSE ) { _TMP_FUNC = (int (*)())signal(SIGUSR1, STD_go); pause(); - signal(SIGUSR1, (void (*)())_TMP_FUNC); + signal(SIGUSR1, (_sig_func_ptr)_TMP_FUNC); } @@ -693,8 +697,7 @@ get_current_time() * counter integer is supplied by the user program. ***********************************************************************/ int -usc_test_looping(counter) -int counter; +usc_test_looping(int counter) { static int first_time = 1; static int stop_time = 0; /* stop time in rtc or usecs */ @@ -803,10 +806,11 @@ int counter; * This function recressively calls itself max times. */ static void -usc_recressive_func(cnt, max, bstack) -int cnt; -int max; -struct usc_bigstack_t bstack; +usc_recressive_func( + int cnt, + int max, + struct usc_bigstack_t **bstack +) { if ( cnt < max ) usc_recressive_func(cnt+1, max, bstack); diff --git a/winsup/testsuite/libltp/lib/pattern.c b/winsup/testsuite/libltp/lib/pattern.c index 7f4d5873e0..5a88bfd3b8 100644 --- a/winsup/testsuite/libltp/lib/pattern.c +++ b/winsup/testsuite/libltp/lib/pattern.c @@ -38,12 +38,13 @@ */ int -pattern_check(buf, buflen, pat, patlen, patshift) -char *buf; -int buflen; -char *pat; -int patlen; -int patshift; +pattern_check( + char *buf, + int buflen, + char *pat, + int patlen, + int patshift +) { int nb, ncmp, nleft; char *cp; @@ -105,12 +106,13 @@ int patshift; } int -pattern_fill(buf, buflen, pat, patlen, patshift) -char *buf; -int buflen; -char *pat; -int patlen; -int patshift; +pattern_fill( + char *buf, + int buflen, + char *pat, + int patlen, + int patshift +) { int trans, ncopied, nleft; char *cp; diff --git a/winsup/testsuite/libltp/lib/search_path.c b/winsup/testsuite/libltp/lib/search_path.c index 697b4037b2..f6936094a1 100644 --- a/winsup/testsuite/libltp/lib/search_path.c +++ b/winsup/testsuite/libltp/lib/search_path.c @@ -103,11 +103,12 @@ char **argv; /* */ int -search_path(cmd, res_path, access_mode, fullpath) -const char *cmd; /* The requested filename */ -char *res_path; /* The resulting path or error mesg */ -int access_mode; /* the mode used by access(2) */ -int fullpath; /* if set, cwd will be prepended to all non-full paths */ +search_path( + const char *cmd, /* The requested filename */ + char *res_path, /* The resulting path or error mesg */ + int access_mode, /* the mode used by access(2) */ + int fullpath /* if set, cwd will be prepended to all non-full paths */ +) { char *cp; /* used to scan PATH for directories */ int ret; /* return value from access */ diff --git a/winsup/testsuite/libltp/lib/str_to_bytes.c b/winsup/testsuite/libltp/lib/str_to_bytes.c index beecb71b61..70157dcdee 100644 --- a/winsup/testsuite/libltp/lib/str_to_bytes.c +++ b/winsup/testsuite/libltp/lib/str_to_bytes.c @@ -75,8 +75,7 @@ #define T_MULT 1099511627776 /* tera or 2^40 */ int -str_to_bytes(s) -char *s; +str_to_bytes(char *s) { char mult, junk; int nconv; @@ -110,8 +109,7 @@ char *s; } long -str_to_lbytes(s) -char *s; +str_to_lbytes(char *s) { char mult, junk; long nconv; @@ -150,8 +148,7 @@ char *s; */ long long -str_to_llbytes(s) -char *s; +str_to_llbytes(char *s) { char mult, junk; long nconv; diff --git a/winsup/testsuite/libltp/lib/string_to_tokens.c b/winsup/testsuite/libltp/lib/string_to_tokens.c index 6f0d775dd9..a2b3a76174 100644 --- a/winsup/testsuite/libltp/lib/string_to_tokens.c +++ b/winsup/testsuite/libltp/lib/string_to_tokens.c @@ -80,7 +80,7 @@ int string_to_tokens(char *arg_string, char *arg_array[], int array_size, char *separator) { int num_toks = 0; /* number of tokens found */ - char *strtok(); + char *strtok(char *, const char *); if ( arg_array == NULL || array_size <= 1 || separator == NULL ) return -1; diff --git a/winsup/testsuite/libltp/lib/tst_res.c b/winsup/testsuite/libltp/lib/tst_res.c index 99767ec9ba..731dcbc1b4 100644 --- a/winsup/testsuite/libltp/lib/tst_res.c +++ b/winsup/testsuite/libltp/lib/tst_res.c @@ -563,8 +563,6 @@ tst_exit() int tst_environ() { - FILE *fdopen(); - if ( (T_out = fdopen(dup(fileno(stdout)), "w")) == NULL ) return(-1); else diff --git a/winsup/testsuite/libltp/lib/tst_sig.c b/winsup/testsuite/libltp/lib/tst_sig.c index f5b64b666c..976b5eecb1 100644 --- a/winsup/testsuite/libltp/lib/tst_sig.c +++ b/winsup/testsuite/libltp/lib/tst_sig.c @@ -81,7 +81,7 @@ void (*T_cleanup)(); /* pointer to cleanup function */ extern int errno; -static void def_handler(); /* default signal handler */ +static void def_handler(int); /* default signal handler */ /**************************************************************************** * tst_sig() : set-up to catch unexpected signals. fork_flag is set to NOFORK @@ -93,7 +93,7 @@ static void def_handler(); /* default signal handler */ ***************************************************************************/ void -tst_sig(int fork_flag, void (*handler)(), void (*cleanup)()) +tst_sig(int fork_flag, void (*handler)(int), void (*cleanup)()) { char mesg[MAXMESG]; /* message buffer for tst_res */ int sig; diff --git a/winsup/testsuite/libltp/lib/write_log.c b/winsup/testsuite/libltp/lib/write_log.c index 8104b05acd..bfbf6adfaa 100644 --- a/winsup/testsuite/libltp/lib/write_log.c +++ b/winsup/testsuite/libltp/lib/write_log.c @@ -115,10 +115,11 @@ static int wlog_rec_unpack(); */ int -wlog_open(wfile, trunc, mode) -struct wlog_file *wfile; -int trunc; -int mode; +wlog_open( + struct wlog_file *wfile, + int trunc, + int mode +) { int omask, oflags; @@ -166,8 +167,7 @@ int mode; */ int -wlog_close(wfile) -struct wlog_file *wfile; +wlog_close(struct wlog_file *wfile) { close(wfile->w_afd); close(wfile->w_rfd); @@ -201,10 +201,11 @@ struct wlog_file *wfile; */ int -wlog_record_write(wfile, wrec, offset) -struct wlog_file *wfile; -struct wlog_rec *wrec; -long offset; +wlog_record_write( + struct wlog_file *wfile, + struct wlog_rec *wrec, + long offset +) { int reclen; char wbuf[WLOG_REC_MAX_SIZE + 2]; @@ -249,11 +250,12 @@ long offset; */ int -wlog_scan_backward(wfile, nrecs, func, data) -struct wlog_file *wfile; -int nrecs; -int (*func)(); -long data; +wlog_scan_backward( + struct wlog_file *wfile, + int nrecs, + int (*func)(struct wlog_rec*, long), + long data +) { int fd, leftover, nbytes, recnum, reclen, rval; off_t offset; @@ -381,10 +383,11 @@ long data; */ static int -wlog_rec_pack(wrec, buf, flag) -struct wlog_rec *wrec; -char *buf; -int flag; +wlog_rec_pack( + struct wlog_rec *wrec, + char *buf, + int flag +) { char *file, *host, *pattern; struct wlog_rec_disk *wrecd; @@ -430,9 +433,10 @@ int flag; } static int -wlog_rec_unpack(wrec, buf) -struct wlog_rec *wrec; -char *buf; +wlog_rec_unpack( + struct wlog_rec *wrec, + char *buf +) { char *file, *host, *pattern; struct wlog_rec_disk *wrecd; From bb854e0f112ce69c52e0511bbfc423577c57f2a0 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Wed, 4 Dec 2024 22:54:18 +0100 Subject: [PATCH 33/50] Cygwin: try_to_bin: transpose deleted file name to valid Unicode chars Since commit 314c2d2fedc5f ("* syscalls.cc (try_to_bin): Handle remote shares as well.") try_to_bin() transposes the .cyg prefix for temporary files to invalid low surrogate halfs on filesystems setting the FILE_UNICODE_ON_DISK flag. This works on NTFS, but not necessarily on other filesystems, which often require all chars in a filename to be valid Unicode chars. Fix this by transposing into the private use area instead. Fixes: 314c2d2fedc5f ("* syscalls.cc (try_to_bin): Handle remote shares as well.") Signed-off-by: Corinna Vinschen (cherry picked from commit 0924d5f1078b368b6e290d11c9f3d57bc7767576) --- winsup/cygwin/release/3.5.5 | 3 +++ winsup/cygwin/syscalls.cc | 10 +++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index 7ccf28abf3..d5063af164 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -51,3 +51,6 @@ Fixes: - Fix frequent page fault caused in Windows Terminal. Addresses: https://cygwin.com/pipermail/cygwin/2024-December/256841.html + +- Fix using invalid chars in temporary file names for deleted files. + Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256813.html diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 1d9308ef46..11033bca5e 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -340,14 +340,14 @@ try_to_bin (path_conv &pc, HANDLE &fh, ACCESS_MASK access, ULONG flags) else { /* Create unique filename. Start with a dot, followed by "cyg" - transposed into the Unicode low surrogate area (U+dc00) on file - systems supporting Unicode (except Samba), followed by the inode - number in hex, followed by a path hash in hex. The combination - allows to remove multiple hardlinks to the same file. */ + transposed to the Unicode private use area in the U+f700 area + on file systems supporting Unicode (except Samba), followed by + the inode number in hex, followed by a path hash in hex. The + combination allows to remove multiple hardlinks to the same file. */ RtlAppendUnicodeToString (&recycler, (pc.fs_flags () & FILE_UNICODE_ON_DISK && !pc.fs_is_samba ()) - ? L".\xdc63\xdc79\xdc67" : L".cyg"); + ? L".\xf763\xf779\xf767" : L".cyg"); pfii = (PFILE_INTERNAL_INFORMATION) infobuf; status = NtQueryInformationFile (fh, &io, pfii, sizeof *pfii, FileInternalInformation); From bbf8484a5b4fb5bcae024c04a8d84e53834e8b79 Mon Sep 17 00:00:00 2001 From: Kito Cheng Date: Thu, 5 Dec 2024 16:39:56 +0800 Subject: [PATCH 34/50] libm/common: Fix nextafter and nextafterf when x == y That according to C99/POSIX, nextafter(x,y) should return y if x==y. [1] NetBSD fix for this: https://github.com/IIJ-NetBSD/netbsd-src/commit/3bc685224189d2b7dfb68da52d9725a256a667bd [2] glibc fix for this: https://github.com/bminor/glibc/commit/bc9f6000f6752153e5e1902259d5f491a88a1ae5#diff-bcc0628a39c3c2003047dcb5a40a8b50c00f01a74b1c8c1100d770a8e48b1ce2 [3] Linux man page: https://man7.org/linux/man-pages/man3/nextafter.3.html (cherry picked from commit 7ccfe49e8ce908c581f82c8dbf0f9064df488a24) --- newlib/libm/common/s_nextafter.c | 2 +- newlib/libm/common/sf_nextafter.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/newlib/libm/common/s_nextafter.c b/newlib/libm/common/s_nextafter.c index 9453a0a001..356c79f3de 100644 --- a/newlib/libm/common/s_nextafter.c +++ b/newlib/libm/common/s_nextafter.c @@ -70,7 +70,7 @@ PORTABILITY if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) || /* x is nan */ ((iy>=0x7ff00000)&&((iy-0x7ff00000)|ly)!=0)) /* y is nan */ return x+y; - if(x==y) return x; /* x=y, return x */ + if(x==y) return y; /* x=y, return y */ if((ix|lx)==0) { /* x == 0 */ INSERT_WORDS(x,hy&0x80000000,1); /* return +-minsubnormal */ y = x*x; diff --git a/newlib/libm/common/sf_nextafter.c b/newlib/libm/common/sf_nextafter.c index cea4da58dd..cdc7c663df 100644 --- a/newlib/libm/common/sf_nextafter.c +++ b/newlib/libm/common/sf_nextafter.c @@ -32,7 +32,7 @@ if(FLT_UWORD_IS_NAN(ix) || FLT_UWORD_IS_NAN(iy)) return x+y; - if(x==y) return x; /* x=y, return x */ + if(x==y) return y; /* x=y, return y */ if(FLT_UWORD_IS_ZERO(ix)) { /* x == 0 */ SET_FLOAT_WORD(x,(hy&0x80000000)|FLT_UWORD_MIN); y = x*x; From a951054d992dbd379c2336101515fd9e8ad8a882 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Mon, 25 Nov 2024 19:51:53 +0900 Subject: [PATCH 35/50] Cygwin: signal: Fix deadlock between main thread and sig thread Previously, a deadlock happened if many SIGSTOP/SIGCONT signals were received rapidly. If the main thread sends __SIGFLUSH at the timing when SIGSTOP is handled by the sig thread, but not is handled by the main thread yet (sig_handle_tty_stop() not called yet), and if SIGCONT is received, the sig thread waits for cygtls::current_sig (is SIGSTOP now) cleared. However, the main thread waits for the pack.wakeup using WaitForSingleObject(), so the main thread cannot handle SIGSTOP. This is the mechanism of the deadlock. This patch uses cygwait() instead of WaitForSingleObject() to be able to handle the pending SIGSTOP. Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256744.html Fixes: 7759daa979c4 ("(sig_send): Fill out sigpacket structure to send to signal thread rather than racily sending separate packets.") Reported-by: Christian Franke Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit d243e51ef1d30312ba1e21b4d25a1ca9a8dc1f63) --- winsup/cygwin/sigproc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index a758bc8f2c..2e813b3a7e 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -760,7 +760,7 @@ sig_send (_pinfo *p, siginfo_t& si, _cygtls *tls) if (wait_for_completion) { sigproc_printf ("Waiting for pack.wakeup %p", pack.wakeup); - rc = WaitForSingleObject (pack.wakeup, WSSC); + rc = cygwait (pack.wakeup, WSSC); ForceCloseHandle (pack.wakeup); } else From 09be373e4594345e65ef966122a85fc35a35cef3 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Mon, 25 Nov 2024 20:19:06 +0900 Subject: [PATCH 36/50] Cygwin: signal: Handle queued signal without explicit __SIGFLUSH With the previous code, the queued signal is tried to resend only when a new signal arrives or pending_signals::pending() is called. With this patch, if the signal is queued and the retry flag is not set and the new signal is not received yet, the sig thread tries to handle the queued signal again. Without this patch, the chance to handle the queue would be delayed. Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256744.html Fixes: 5e31c80e4e8d ("(pending_signals::pending): Force an additional loop through wait_sig by setting retry whenever this function is called.") Reported-by: Christian Franke Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit e10f822a2b39bade20858ba3c704a8bb7d965cb4) --- winsup/cygwin/sigproc.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 2e813b3a7e..ecf79bc712 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -1321,6 +1321,9 @@ wait_sig (VOID *) sigpacket pack = {}; if (sigq.retry) pack.si.si_signo = __SIGFLUSH; + else if (sigq.start.next + && PeekNamedPipe (my_readsig, NULL, 0, NULL, &nb, NULL) && !nb) + pack.si.si_signo = __SIGFLUSH; else if (!ReadFile (my_readsig, &pack, sizeof (pack), &nb, NULL)) Sleep (INFINITE); /* Assume were exiting. Never exit this thread */ else if (nb != sizeof (pack) || !pack.si.si_signo) From e1b6996e7bfacac3f0b93bbf9f1c40a7c734eeb3 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Mon, 25 Nov 2024 20:55:44 +0900 Subject: [PATCH 37/50] Cygwin: signal: Drop unnecessary queue flush Previously, the retry flag was always set when pending_signal::pending() was called. However, if the queue is empty sig thread tries to flush the queue even though it is not necessary. With this patch, the retry flag is set only if the queue is not empty. Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256744.html Fixes: 5e31c80e4e8d ("(pending_signals::pending): Force an additional loop through wait_sig by setting retry whenever this function is called.") Reported-by: Christian Franke Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit 57ce5f1e0bf4a6fef7173b2549edc4f2090dd0e7) --- winsup/cygwin/sigproc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index ecf79bc712..618cc45565 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -110,7 +110,7 @@ class pending_signals public: void add (sigpacket&); - bool pending () {retry = true; return !!start.next;} + bool pending () {retry = !!start.next; return retry;} void clear (int sig) {sigs[sig].si.si_signo = 0;} void clear (_cygtls *tls); friend void sig_dispatch_pending (bool); From f930a973bd98dfa2ade96e2ae2c4e39554a80f5f Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Wed, 27 Nov 2024 20:03:55 +0900 Subject: [PATCH 38/50] Cygwin: signal: Fix another deadlock between main and sig thread In _cygtls::handle_SIGCONT(), the sig thread waits for the main thread to process the signal without unlocking the TLS area. This causes a deadlock if the main thread tries to acquire a lock for the TLS area in the meantime. With this patch, unlock the TLS before calling yield() in handle_SIGCONT(). Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256744.html Fixes: 26158dc3e9c2("* exceptions.cc (sigpacket::process): Lock _cygtls area of thread before accessing it.") Reported-by: Christian Franke Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit 9ae51bcc51a7901559c476e6301597760c2726fd) --- winsup/cygwin/exceptions.cc | 10 +++++++--- winsup/cygwin/local_includes/cygtls.h | 4 +++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 60c1f594f8..42556093ad 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -1419,7 +1419,7 @@ api_fatal_debug () /* Attempt to carefully handle SIGCONT when we are stopped. */ void -_cygtls::handle_SIGCONT () +_cygtls::handle_SIGCONT (threadlist_t * &tl_entry) { if (NOTSTATE (myself, PID_STOPPED)) return; @@ -1434,7 +1434,11 @@ _cygtls::handle_SIGCONT () while (1) if (sig) /* Assume that it's ok to just test sig outside of a lock since setup_handler does it this way. */ - yield (); /* Attempt to schedule another thread. */ + { + cygheap->unlock_tls (tl_entry); + yield (); /* Attempt to schedule another thread. */ + tl_entry = cygheap->find_tls (_main_tls); + } else if (sigsent) break; /* SIGCONT has been recognized by other thread */ else @@ -1476,7 +1480,7 @@ sigpacket::process () if (si.si_signo == SIGCONT) { tl_entry = cygheap->find_tls (_main_tls); - _main_tls->handle_SIGCONT (); + _main_tls->handle_SIGCONT (tl_entry); cygheap->unlock_tls (tl_entry); } diff --git a/winsup/cygwin/local_includes/cygtls.h b/winsup/cygwin/local_includes/cygtls.h index f67e9136c3..f967bb9cc2 100644 --- a/winsup/cygwin/local_includes/cygtls.h +++ b/winsup/cygwin/local_includes/cygtls.h @@ -159,6 +159,8 @@ extern "C" int __ljfault (jmp_buf, int); typedef uintptr_t __tlsstack_t; +struct threadlist_t; + class _cygtls { public: /* Do NOT remove this public: line, it's a marker for gentls_offsets. */ @@ -262,7 +264,7 @@ class _cygtls { will_wait_for_signal = false; } - void handle_SIGCONT (); + void handle_SIGCONT (threadlist_t * &); static void cleanup_early(struct _reent *); private: void call2 (DWORD (*) (void *, void *), void *, void *); From 3a28aac4283c68e96b86ecc3a573b1e7df60dde6 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Sat, 23 Nov 2024 11:25:56 +0100 Subject: [PATCH 39/50] Cygwin: gendef: unify comments in terms of acquiring/releasing stacklock Various forms of describing what we do with the stacklock are used. Try to be consistent. Signed-off-by: Corinna Vinschen (cherry picked from commit 63804a28b330ccda7e1ef1c04d2d1c5e22a8e40d) --- winsup/cygwin/scripts/gendef | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/winsup/cygwin/scripts/gendef b/winsup/cygwin/scripts/gendef index c2ad5c75e3..fae7a7f313 100755 --- a/winsup/cygwin/scripts/gendef +++ b/winsup/cygwin/scripts/gendef @@ -132,8 +132,8 @@ _sigfe_maybe: # stack is aligned on entry! _sigfe: # stack is aligned on entry! .seh_endprologue movq %gs:8,%r10 # location of bottom of stack -1: movl \$1,%r11d # potential lock value - xchgl %r11d,_cygtls.stacklock(%r10) # see if we can grab it +1: movl \$1,%r11d + xchgl %r11d,_cygtls.stacklock(%r10) # try to acquire lock movl %r11d,_cygtls.spinning(%r10) # flag if we are waiting for lock testl %r11d,%r11d # it will be zero jz 2f # if so @@ -145,7 +145,7 @@ _sigfe: # stack is aligned on entry! xchgq %r11,8(%rsp) # exchange with real return value movq %r11,(%rax) # store real return value on alt stack incl _cygtls.incyg(%r10) - decl _cygtls.stacklock(%r10) # remove lock + decl _cygtls.stacklock(%r10) # release lock popq %rax # pop real function address from stack jmp *%rax # and jmp to it .seh_endproc @@ -156,8 +156,8 @@ _sigbe: # return here after cygwin syscall # stack is aligned on entry! .seh_endprologue movq %gs:8,%r10 # address of bottom of tls -1: movl \$1,%r11d # potential lock value - xchgl %r11d,_cygtls.stacklock(%r10) # see if we can grab it +1: movl \$1,%r11d + xchgl %r11d,_cygtls.stacklock(%r10) # try to acquire lock movl %r11d,_cygtls.spinning(%r10) # flag if we are waiting for lock testl %r11d,%r11d # it will be zero jz 2f # if so @@ -241,8 +241,8 @@ sigdelayed: addq %r12,%rcx # and store as first arg to method call _ZN7_cygtls19call_signal_handlerEv # call handler -1: movl \$1,%r11d # potential lock value - xchgl %r11d,_cygtls.stacklock(%r12) # see if we can grab it +1: movl \$1,%r11d + xchgl %r11d,_cygtls.stacklock(%r12) # try to acquire lock movl %r11d,_cygtls.spinning(%r12) # flag if we are waiting for lock testl %r11d,%r11d # it will be zero jz 2f # if so @@ -258,7 +258,7 @@ sigdelayed: xchgq %r10,-8(%r11) # get return address from signal stack xorl %r11d,%r11d movl %r11d,_cygtls.incyg(%r12) - movl %r11d,_cygtls.stacklock(%r12) # unlock + movl %r11d,_cygtls.stacklock(%r12) # release lock movdqa 0x20(%rsp),%xmm0 movdqa 0x30(%rsp),%xmm1 movdqa 0x40(%rsp),%xmm2 @@ -321,7 +321,7 @@ _ZN7_cygtls4lockEv: .seh_endprologue movq %rcx,%r12 1: movl \$1,%r11d - xchgl %r11d,_cygtls.stacklock_p(%r12) + xchgl %r11d,_cygtls.stacklock_p(%r12) # try to acquire lock testl %r11d,%r11d jz 2f pause @@ -335,7 +335,7 @@ _ZN7_cygtls4lockEv: .seh_proc _ZN7_cygtls6unlockEv _ZN7_cygtls6unlockEv: .seh_endprologue - decl _cygtls.stacklock_p(%rcx) + decl _cygtls.stacklock_p(%rcx) # release lock ret .seh_endproc @@ -357,7 +357,7 @@ stabilize_sig_stack: .seh_endprologue movq %gs:8,%r12 1: movl \$1,%r10d - xchgl %r10d,_cygtls.stacklock(%r12) + xchgl %r10d,_cygtls.stacklock(%r12) # try to acquire lock movl %r10d,_cygtls.spinning(%r12) # flag if we are waiting for lock testl %r10d,%r10d jz 2f @@ -366,7 +366,7 @@ stabilize_sig_stack: 2: incl _cygtls.incyg(%r12) cmpl \$0,_cygtls.sig(%r12) jz 3f - decl _cygtls.stacklock(%r12) # unlock + decl _cygtls.stacklock(%r12) # release lock movq \$_cygtls.start_offset,%rcx # point to beginning addq %r12,%rcx # of tls block call _ZN7_cygtls19call_signal_handlerEv @@ -443,7 +443,7 @@ setjmp: popq %rcx movq _cygtls.stackptr(%r11),%r10 movq %r10,(%rcx) - decl _cygtls.stacklock(%r11) + decl _cygtls.stacklock(%r11) # release lock xorl %eax,%eax ret .seh_endproc @@ -480,7 +480,7 @@ longjmp: movl %r12d,%eax # restore return value movq (%rcx),%r10 # get old signal stack movq %r10,_cygtls.stackptr(%r11) # restore - decl _cygtls.stacklock(%r11) # relinquish lock + decl _cygtls.stacklock(%r11) # release lock xorl %r10d,%r10d movl %r10d,_cygtls.incyg(%r11) # we're not in cygwin anymore movq 0x8(%rcx),%rbx From da6d5f838c19aeaacbda85b6fe3f27c022d12f1c Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Fri, 29 Nov 2024 17:08:46 +0900 Subject: [PATCH 40/50] Cygwin: cygtls: Prompt system to switch tasks explicitly in lock() This patch calls Sleep(0) in the wait loop in lock() to increase the chance of being unlocked in other threads. The lock(), unlock() and locked() are moved from sigfe.s to cygtls.h so that allows inline expansion. Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256744.html Fixes: 61522196c715 ("* Merge in cygwin-64bit-branch.") Reported-by: Christian Franke Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit 9b7a84d24aa17bdd727eb402cc544fa36f4d812e) --- winsup/cygwin/local_includes/cygtls.h | 19 +++++++++++--- winsup/cygwin/scripts/gendef | 36 --------------------------- 2 files changed, 15 insertions(+), 40 deletions(-) diff --git a/winsup/cygwin/local_includes/cygtls.h b/winsup/cygwin/local_includes/cygtls.h index f967bb9cc2..23ef1701a5 100644 --- a/winsup/cygwin/local_includes/cygtls.h +++ b/winsup/cygwin/local_includes/cygtls.h @@ -197,7 +197,7 @@ class _cygtls int sig; unsigned incyg; unsigned spinning; - unsigned stacklock; + volatile unsigned stacklock; __tlsstack_t *stackptr; __tlsstack_t stack[TLS_STACK_SIZE]; unsigned initialized; @@ -225,9 +225,20 @@ class _cygtls int call_signal_handler (); void remove_wq (DWORD); void fixup_after_fork (); - void lock (); - void unlock (); - bool locked (); + void lock () + { + while (InterlockedExchange (&stacklock, 1)) + { +#ifdef __x86_64__ + __asm__ ("pause"); +#else +#error unimplemented for this target +#endif + Sleep (0); + } + } + void unlock () { stacklock = 0; } + bool locked () { return !!stacklock; } HANDLE get_signal_arrived (bool wait_for_lock = true) { if (!signal_arrived) diff --git a/winsup/cygwin/scripts/gendef b/winsup/cygwin/scripts/gendef index fae7a7f313..bb87ab55e5 100755 --- a/winsup/cygwin/scripts/gendef +++ b/winsup/cygwin/scripts/gendef @@ -312,42 +312,6 @@ _ZN7_cygtls3popEv: ret .seh_endproc -# _cygtls::lock - .global _ZN7_cygtls4lockEv - .seh_proc _ZN7_cygtls4lockEv -_ZN7_cygtls4lockEv: - pushq %r12 - .seh_pushreg %r12 - .seh_endprologue - movq %rcx,%r12 -1: movl \$1,%r11d - xchgl %r11d,_cygtls.stacklock_p(%r12) # try to acquire lock - testl %r11d,%r11d - jz 2f - pause - jmp 1b -2: popq %r12 - ret - .seh_endproc - -# _cygtls::unlock - .global _ZN7_cygtls6unlockEv - .seh_proc _ZN7_cygtls6unlockEv -_ZN7_cygtls6unlockEv: - .seh_endprologue - decl _cygtls.stacklock_p(%rcx) # release lock - ret - .seh_endproc - -# _cygtls::locked - .global _ZN7_cygtls6lockedEv - .seh_proc _ZN7_cygtls6lockedEv -_ZN7_cygtls6lockedEv: - .seh_endprologue - movl _cygtls.stacklock_p(%rcx),%eax - ret - .seh_endproc - .seh_proc stabilize_sig_stack stabilize_sig_stack: pushq %r12 From 8fa1c02625c9c962690291fc6dcd6685ed110544 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Fri, 29 Nov 2024 17:13:32 +0900 Subject: [PATCH 41/50] Cygwin: signal: Fix a short period of deadlock The main thread waits for the sig thread to read the signal pipe by calling Sleep(10) if writing to the signal pipe has failed. However, if the signal thread waiting for another signal being handled in the main thread, the sig thread does not read the signal pipe. To avoid such a situation, this patch replaces Sleep(10) to cygwait(). Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256744.html Fixes: 6f05b327678f ("(sig_send): Retry WriteFiles which fail when there is no error but packbytes have not been sent.") Reported-by: Christian Franke Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit 2544e753963e9c15a9e3fe35188d8dea7b39d748) --- winsup/cygwin/sigproc.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 618cc45565..601147ff6c 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -727,7 +727,8 @@ sig_send (_pinfo *p, siginfo_t& si, _cygtls *tls) res = WriteFile (sendsig, leader, packsize, &nb, NULL); if (!res || packsize == nb) break; - Sleep (10); + if (cygwait (NULL, 10, cw_sig_eintr) == WAIT_SIGNALED) + _my_tls.call_signal_handler (); res = 0; } From e9fdf6f420090a800f3e41dd730d53c0cf5b5f8b Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Fri, 29 Nov 2024 16:58:05 +0900 Subject: [PATCH 42/50] Cygwin: signal: Optimize the priority of the sig thread Previously, the sig thread ran in THREAD_PRIORITY_HIGHEST priority. This causes a critical delay in the signal handling in the main thread if too many signals are received rapidly and the CPU is very busy. In this case, most of the CPU time is allocated to the sig thread, so the main thread cannot have a chance of handling signals. With this patch, to avoid such a situation, the priority of the sig thread is set to THREAD_PRIORITY_NORMAL priority. Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256744.html Fixes: 53ad6f1394aa ("(cygthread::cygthread): Use three only arguments for detached threads, and start the thread via QueueUserAPC/async_create.") Reported-by: Christian Franke Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit 9a274a967d1fe9a28d0d658749b08e65d09d3ee0) --- winsup/cygwin/sigproc.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 601147ff6c..3fe6447e54 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -1316,6 +1316,7 @@ wait_sig (VOID *) hntdll = GetModuleHandle ("ntdll.dll"); + SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_NORMAL); for (;;) { DWORD nb; From 7adfc92401cb00b9a59b25a792a5d5f6dc1220a6 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Tue, 3 Dec 2024 22:14:44 +0900 Subject: [PATCH 43/50] Cygwin: signal: Increase chance of handling signal in main thread If the process() fails and the signal remains in the queue, the most possible reason is that the target thread is already armed by another signal and does not handle it yet. With this patch, to increase the chance of handling it in the other threads, call yield() before retrying process(). Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256744.html Fixes: e10f822a2b39 ("Cygwin: signal: Handle queued signal without explicit __SIGFLUSH") Reported-by: Christian Franke Reviewed-by: Signed-off-by: Takashi Yano (cherry picked from commit c48d58d838d90df6247123c487686699742d75de) --- winsup/cygwin/sigproc.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 3fe6447e54..b9669a8616 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -1325,7 +1325,10 @@ wait_sig (VOID *) pack.si.si_signo = __SIGFLUSH; else if (sigq.start.next && PeekNamedPipe (my_readsig, NULL, 0, NULL, &nb, NULL) && !nb) - pack.si.si_signo = __SIGFLUSH; + { + yield (); + pack.si.si_signo = __SIGFLUSH; + } else if (!ReadFile (my_readsig, &pack, sizeof (pack), &nb, NULL)) Sleep (INFINITE); /* Assume were exiting. Never exit this thread */ else if (nb != sizeof (pack) || !pack.si.si_signo) From 60fa8d793f867d896b824c66789c48e86dec4ea7 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Wed, 4 Dec 2024 13:50:17 +0100 Subject: [PATCH 44/50] Cygwin: setjmp/longjmp: decrement incyg after signal handling Commit 0b6fbd396ca2f ("* exceptions.cc (_cygtls::interrupt_now): Revert to checking for "spinning" when choosing to defer signal.") introduced a bug in the loop inside the stabilize_sig_stack subroutine: First, stabilize_sig_stack grabs the stacklock. The _cygtls::incyg flag is then incremented before checking if a signal has to be handled for the current thread. If no signal waits, the code simply jumps out, decrements _cygtls::incyg and returns to the caller, which eventually releases the stacklock. However, if a signal is waiting, stabilize_sig_stack releases the stacklock, calls _cygtls::call_signal_handler(), and returns to the start of the subroutine, trying to grab the lock. After grabbing the lock, it increments _cygtls::incyg... wait... again? The loop does not decrement _cygtls::incyg after _cygtls::call_signal_handler(), which returns with _cygtls::incyg set to 1. So it increments incyg to 2. If no other signal is waiting, stabilize_sig_stack jumps out and decrements _cygtls::incyg to 1. Eventually, setjmp or longjmp both will return to user code with _cygtls::incyg set to 1. This *may* be fixed at some later point when signals arrive, but there will be a time when the application runs in user code with broken signal handling. Fixes: 0b6fbd396ca2f ("* exceptions.cc (_cygtls::interrupt_now): Revert to checking for "spinning" when choosing to defer signal.") Signed-off-by: Corinna Vinschen (cherry picked from commit 41e1013e6846f1774dfec085ff983990f67e6437) --- winsup/cygwin/scripts/gendef | 1 + 1 file changed, 1 insertion(+) diff --git a/winsup/cygwin/scripts/gendef b/winsup/cygwin/scripts/gendef index bb87ab55e5..e02d3503cc 100755 --- a/winsup/cygwin/scripts/gendef +++ b/winsup/cygwin/scripts/gendef @@ -334,6 +334,7 @@ stabilize_sig_stack: movq \$_cygtls.start_offset,%rcx # point to beginning addq %r12,%rcx # of tls block call _ZN7_cygtls19call_signal_handlerEv + decl _cygtls.incyg(%r12) jmp 1b 3: decl _cygtls.incyg(%r12) addq \$0x20,%rsp From 52d1c851fb0dfa16461d83fdfa4d70643b996edc Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Thu, 5 Dec 2024 21:15:13 +0100 Subject: [PATCH 45/50] Cygwin: cygtls: add volatile qualifier to spinning Given that spinning is only checked once at the start of a _cygtls::interrupt_now() which is called in a loop, it's probably not necessary to mark _cygtls::spinning as volatile. However, spinning is changed from assembler code and we don't want the compiler to make funny assumptions, so, better safe than sorry. Signed-off-by: Corinna Vinschen (cherry picked from commit 3a9fb7c561d9e8a78e444dd3920c57e857a92baa) --- winsup/cygwin/local_includes/cygtls.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winsup/cygwin/local_includes/cygtls.h b/winsup/cygwin/local_includes/cygtls.h index 23ef1701a5..e4e3889aff 100644 --- a/winsup/cygwin/local_includes/cygtls.h +++ b/winsup/cygwin/local_includes/cygtls.h @@ -196,7 +196,7 @@ class _cygtls waitq wq; int sig; unsigned incyg; - unsigned spinning; + volatile unsigned spinning; volatile unsigned stacklock; __tlsstack_t *stackptr; __tlsstack_t stack[TLS_STACK_SIZE]; From 9c34e029918d482eef9fb4305530cb581f42dbe6 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Thu, 5 Dec 2024 18:34:02 +0100 Subject: [PATCH 46/50] Cygwin: setjmp/longjmp: drop setting spinning flag Per the comment in _cygtls::interrupt_now(), the spinning flag is supposed to guard that the targeted thread is about to enter the Cygwin DLL. Setting spinning has then been added to _sigfe, _sigbe, sigdelayed and stabilize_sig_stack, the latter being called from setjmp/longjmp. However, setjmp/longjmp only enter the DLL in case of a pending signal, calling _cygtls::call_signal_handler(). This in turn is already guarded by setting the incyg flag, and there's no other action in stabilize_sig_stack which might interfere with the signal setup. All the rest of setjmp/longjmp is plain userspace. Therefore, drop setting the spinning flag from stabilize_sig_stack, because it results in dropped signals in tight longjmp loops. Fixes: edc4f86ad2827 ("* Makefile.in (clean): Remove sigfe.s.") Signed-off-by: Corinna Vinschen (cherry picked from commit 96d856320a1d740546eaf8a6c0ddb3d489e10492) --- winsup/cygwin/scripts/gendef | 1 - 1 file changed, 1 deletion(-) diff --git a/winsup/cygwin/scripts/gendef b/winsup/cygwin/scripts/gendef index e02d3503cc..bbd5f27413 100755 --- a/winsup/cygwin/scripts/gendef +++ b/winsup/cygwin/scripts/gendef @@ -322,7 +322,6 @@ stabilize_sig_stack: movq %gs:8,%r12 1: movl \$1,%r10d xchgl %r10d,_cygtls.stacklock(%r12) # try to acquire lock - movl %r10d,_cygtls.spinning(%r12) # flag if we are waiting for lock testl %r10d,%r10d jz 2f pause From 2f9258b1c585b910c9d837af3d33f54e71e17ae2 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Thu, 5 Dec 2024 22:28:19 +0100 Subject: [PATCH 47/50] Cygwin: Add setjmp/longjmp fix to 3.5.5 release messages Signed-off-by: Corinna Vinschen (cherry picked from commit f71550e0dbef51e0a4a706edae49c33c5372db19) --- winsup/cygwin/release/3.5.5 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index d5063af164..7eece3bbdb 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -54,3 +54,6 @@ Fixes: - Fix using invalid chars in temporary file names for deleted files. Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256813.html + +- Fix losing signals during setjmp/longjmp. + Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256808.html From 5bd4f9936f20ef5f06dc11986271744bf6d87359 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Fri, 29 Nov 2024 16:46:48 +0900 Subject: [PATCH 48/50] Cygwin: signal: Remove queue entry from the queue chain when cleared The queue is cleaned up by removing the entries having si_signo == 0 while processing the queued signals, however, sigpacket::process() may set si_signo in the queue to 0 of the entry already processed but not succeed by calling sig_clear(). This patch ensures the sig_clear() to remove the entry from the queue chain. For this purpose, the pointer prev has been added to the sigpacket. This is to handle the following case appropriately. Consider the queued signal chain of: A->B->C->D without pointer prev. Assume that the pointer 'q' and 'qnext' point to C, and process() is processing C. If B is cleared in process(), A->next should be set to to C in sigpacket::clear(). Then, if process() for C succeeds, C should be removed from the queue, so A->next should be set to D. However, we cannot do that because we do not have the pointer to A in the while loop in wait_sig(). With the pointer prev, we can easily access A and C in sigpacket::clear() as well as A and D in the while loop in wait_sig() using the pointer prev and next without pursuing the chain. Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256744.html Fixes: 9d2155089e87 ("(wait_sig): Define variable q to be the start of the signal queue. Just iterate through sigq queue, deleting processed or zeroed signals") Reported-by: Christian Franke Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit d565aca46f06117ef16ec37c51767a5e140ee9e2) --- winsup/cygwin/local_includes/sigproc.h | 3 +- winsup/cygwin/sigproc.cc | 48 +++++++++++++++++--------- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/winsup/cygwin/local_includes/sigproc.h b/winsup/cygwin/local_includes/sigproc.h index 7aca80595d..41745f214c 100644 --- a/winsup/cygwin/local_includes/sigproc.h +++ b/winsup/cygwin/local_includes/sigproc.h @@ -51,8 +51,9 @@ struct sigpacket { HANDLE wakeup; HANDLE thread_handle; - struct sigpacket *next; }; + struct sigpacket *next; + struct sigpacket *prev; int process (); int setup_handler (void *, struct sigaction&, _cygtls *); }; diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index b9669a8616..287e78ff52 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -111,7 +111,7 @@ class pending_signals public: void add (sigpacket&); bool pending () {retry = !!start.next; return retry;} - void clear (int sig) {sigs[sig].si.si_signo = 0;} + void clear (int sig); void clear (_cygtls *tls); friend void sig_dispatch_pending (bool); friend void wait_sig (VOID *arg); @@ -432,21 +432,35 @@ sig_clear (int sig) sigq.clear (sig); } +/* Clear pending signals of specific si_signo. + Called from sigpacket::process(). */ +void +pending_signals::clear (int sig) +{ + sigpacket *q = sigs + sig; + if (!sig || !q->si.si_signo) + return; + q->si.si_signo = 0; + q->prev->next = q->next; + if (q->next) + q->next->prev = q->prev; +} + /* Clear pending signals of specific thread. Called under TLS lock from _cygtls::remove_pending_sigs. */ void pending_signals::clear (_cygtls *tls) { - sigpacket *q = &start, *qnext; + sigpacket *q = &start; - while ((qnext = q->next)) - if (qnext->sigtls == tls) + while ((q = q->next)) + if (q->sigtls == tls) { - qnext->si.si_signo = 0; - q->next = qnext->next; + q->si.si_signo = 0; + q->prev->next = q->next; + if (q->next) + q->next->prev = q->prev; } - else - q = qnext; } /* Clear pending signals of specific thread. Called from _cygtls::remove */ @@ -1300,7 +1314,10 @@ pending_signals::add (sigpacket& pack) return; *se = pack; se->next = start.next; - start.next = se; + se->prev = &start; + se->prev->next = se; + if (se->next) + se->next->prev = se; } /* Process signals by waiting for signal data to arrive in a pipe. @@ -1455,17 +1472,16 @@ wait_sig (VOID *) case __SIGFLUSHFAST: if (!sig_held) { - sigpacket *qnext; /* Check the queue for signals. There will always be at least one thing on the queue if this was a valid signal. */ - while ((qnext = q->next)) + while ((q = q->next)) { - if (qnext->si.si_signo && qnext->process () <= 0) - q = qnext; - else + if (q->si.si_signo && q->process () > 0) { - q->next = qnext->next; - qnext->si.si_signo = 0; + q->si.si_signo = 0; + q->prev->next = q->next; + if (q->next) + q->next->prev = q->prev; } } /* At least one signal still queued? The event is used in select From b38ba4b9af354de8520ed0e44286a4e0431ccdc3 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Wed, 4 Dec 2024 11:53:41 +0900 Subject: [PATCH 49/50] Cygwin: signal: Introduce a lock for the signal queue Currently, the signal queue is touched by the thread sig as well as other threads that call sigaction_worker(). This potentially has a possibility to destroy the signal queue chain. A possible worst result may be a self-loop chain which causes infinite loop. With this patch, lock()/unlock() are introduce to avoid such a situation. Fixes: 474048c26edf ("* sigproc.cc (pending_signals::add): Just index directly into signal array rather than treating the array as a heap.") Suggested-by: Corinna Vinschen Reviewed-by: Corinna Vinschen Signed-off-by: Takashi Yano (cherry picked from commit 496fa7b2ce0052550eab8900723ebb59c33d25e7) --- winsup/cygwin/exceptions.cc | 12 +++++------ winsup/cygwin/local_includes/sigproc.h | 2 +- winsup/cygwin/signal.cc | 4 ++-- winsup/cygwin/sigproc.cc | 28 +++++++++++++++++++++----- 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 42556093ad..a560a3f344 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -1448,10 +1448,10 @@ _cygtls::handle_SIGCONT (threadlist_t * &tl_entry) sigsent = true; } /* Clear pending stop signals */ - sig_clear (SIGSTOP); - sig_clear (SIGTSTP); - sig_clear (SIGTTIN); - sig_clear (SIGTTOU); + sig_clear (SIGSTOP, false); + sig_clear (SIGTSTP, false); + sig_clear (SIGTTIN, false); + sig_clear (SIGTTOU, false); } int @@ -1552,14 +1552,14 @@ sigpacket::process () goto exit_sig; if (si.si_signo == SIGSTOP) { - sig_clear (SIGCONT); + sig_clear (SIGCONT, false); goto stop; } /* Clear pending SIGCONT on stop signals */ if (si.si_signo == SIGTSTP || si.si_signo == SIGTTIN || si.si_signo == SIGTTOU) - sig_clear (SIGCONT); + sig_clear (SIGCONT, false); if (handler == (void *) SIG_DFL) { diff --git a/winsup/cygwin/local_includes/sigproc.h b/winsup/cygwin/local_includes/sigproc.h index 41745f214c..7573aa14c5 100644 --- a/winsup/cygwin/local_includes/sigproc.h +++ b/winsup/cygwin/local_includes/sigproc.h @@ -63,7 +63,7 @@ void set_signal_mask (sigset_t&, sigset_t); int handle_sigprocmask (int sig, const sigset_t *set, sigset_t *oldset, sigset_t& opmask); -void sig_clear (int); +void sig_clear (int, bool); void sig_set_pending (int); int handle_sigsuspend (sigset_t); diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc index 9ee6cf9959..fb4983b573 100644 --- a/winsup/cygwin/signal.cc +++ b/winsup/cygwin/signal.cc @@ -451,9 +451,9 @@ sigaction_worker (int sig, const struct sigaction *newact, if (!(gs.sa_flags & SA_NODEFER)) gs.sa_mask |= SIGTOMASK(sig); if (gs.sa_handler == SIG_IGN) - sig_clear (sig); + sig_clear (sig, true); if (gs.sa_handler == SIG_DFL && sig == SIGCHLD) - sig_clear (sig); + sig_clear (sig, true); if (sig == SIGCHLD) { myself->process_state &= ~PID_NOCLDSTOP; diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 287e78ff52..1ab33fc3c2 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -106,12 +106,16 @@ class pending_signals { sigpacket sigs[_NSIG + 1]; sigpacket start; + SRWLOCK queue_lock; bool retry; + void lock () { AcquireSRWLockExclusive (&queue_lock); } + void unlock () { ReleaseSRWLockExclusive (&queue_lock); } public: + pending_signals (): queue_lock (SRWLOCK_INIT) {} void add (sigpacket&); bool pending () {retry = !!start.next; return retry;} - void clear (int sig); + void clear (int sig, bool need_lock); void clear (_cygtls *tls); friend void sig_dispatch_pending (bool); friend void wait_sig (VOID *arg); @@ -427,23 +431,27 @@ proc_terminate () /* Clear pending signal */ void -sig_clear (int sig) +sig_clear (int sig, bool need_lock) { - sigq.clear (sig); + sigq.clear (sig, need_lock); } /* Clear pending signals of specific si_signo. Called from sigpacket::process(). */ void -pending_signals::clear (int sig) +pending_signals::clear (int sig, bool need_lock) { sigpacket *q = sigs + sig; if (!sig || !q->si.si_signo) return; + if (need_lock) + lock (); q->si.si_signo = 0; q->prev->next = q->next; if (q->next) q->next->prev = q->prev; + if (need_lock) + unlock (); } /* Clear pending signals of specific thread. Called under TLS lock from @@ -453,6 +461,7 @@ pending_signals::clear (_cygtls *tls) { sigpacket *q = &start; + lock (); while ((q = q->next)) if (q->sigtls == tls) { @@ -461,6 +470,7 @@ pending_signals::clear (_cygtls *tls) if (q->next) q->next->prev = q->prev; } + unlock (); } /* Clear pending signals of specific thread. Called from _cygtls::remove */ @@ -1313,11 +1323,13 @@ pending_signals::add (sigpacket& pack) if (se->si.si_signo) return; *se = pack; + lock (); se->next = start.next; se->prev = &start; se->prev->next = se; if (se->next) se->next->prev = se; + unlock (); } /* Process signals by waiting for signal data to arrive in a pipe. @@ -1398,6 +1410,7 @@ wait_sig (VOID *) bool issig_wait; *pack.mask = 0; + sigq.lock (); while ((q = q->next)) { _cygtls *sigtls = q->sigtls ?: _main_tls; @@ -1411,6 +1424,7 @@ wait_sig (VOID *) } } } + sigq.unlock (); } break; case __SIGPENDING: @@ -1419,6 +1433,7 @@ wait_sig (VOID *) *pack.mask = 0; tl_entry = cygheap->find_tls (pack.sigtls); + sigq.lock (); while ((q = q->next)) { /* Skip thread-specific signals for other threads. */ @@ -1427,6 +1442,7 @@ wait_sig (VOID *) if (pack.sigtls->sigmask & (bit = SIGTOMASK (q->si.si_signo))) *pack.mask |= bit; } + sigq.unlock (); cygheap->unlock_tls (tl_entry); } break; @@ -1461,7 +1477,7 @@ wait_sig (VOID *) break; default: /* Normal (positive) signal */ if (pack.si.si_signo < 0) - sig_clear (-pack.si.si_signo); + sig_clear (-pack.si.si_signo, true); else sigq.add (pack); fallthrough; @@ -1474,6 +1490,7 @@ wait_sig (VOID *) { /* Check the queue for signals. There will always be at least one thing on the queue if this was a valid signal. */ + sigq.lock (); while ((q = q->next)) { if (q->si.si_signo && q->process () > 0) @@ -1484,6 +1501,7 @@ wait_sig (VOID *) q->next->prev = q->prev; } } + sigq.unlock (); /* At least one signal still queued? The event is used in select only, and only to decide if WFMO should wake up in case a signalfd is waiting via select/poll for being ready to read a From db55d548e395c5b9979b9842a2148a390968fb32 Mon Sep 17 00:00:00 2001 From: Takashi Yano Date: Tue, 26 Nov 2024 13:56:51 +0900 Subject: [PATCH 50/50] Cygwin: Document several fixes for signal handling in release note (cherry picked from commit cfadd852aa5787eb29403efc75bfa637028bfd40) --- winsup/cygwin/release/3.5.5 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/winsup/cygwin/release/3.5.5 b/winsup/cygwin/release/3.5.5 index 7eece3bbdb..e99739241c 100644 --- a/winsup/cygwin/release/3.5.5 +++ b/winsup/cygwin/release/3.5.5 @@ -57,3 +57,7 @@ Fixes: - Fix losing signals during setjmp/longjmp. Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256808.html + +- Fix several problems triggered when a lot of SIGSTOP/SIGCONT signals + are received rapidly. + Addresses: https://cygwin.com/pipermail/cygwin/2024-November/256744.html