Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH] testsuite: Introduce gdb_watchdog (avoid unistd.h/alarm)
@ 2025-08-08 22:50 Pedro Alves
  2025-08-10  3:28 ` Kevin Buettner
  2025-08-12 14:41 ` Tom Tromey
  0 siblings, 2 replies; 7+ messages in thread
From: Pedro Alves @ 2025-08-08 22:50 UTC (permalink / raw)
  To: gdb-patches

There are a good number of testcases in the testsuite that use alarm()
as a watchdog that aborts the test if something goes wrong.

alarm()/SIG_ALRM do not exist on (native) Windows, so those tests fail
to compile there.

For example, testing with x86_64-w64-mingw32-gcc, we see:

 Running /c/rocgdb/src/gdb/testsuite/gdb.base/attach.exp ...
 gdb compile failed, C:/rocgdb/src/gdb/testsuite/gdb.base/attach.c: In function 'main':
 C:/rocgdb/src/gdb/testsuite/gdb.base/attach.c:17:3: error: implicit declaration of function 'alarm' [-Wimplicit-function-declaration]
    17 |   alarm (60);
       |   ^~~~~

While testing with a clang configured to default to
x86_64-pc-windows-msvc, which uses the C/C++ runtime headers from
Visual Studio and has no unistd.h, we get:

 Running /c/rocgdb/src/gdb/testsuite/gdb.base/attach.exp ...
 gdb compile failed, C:/rocgdb/src/gdb/testsuite/gdb.base/attach.c:8:10: fatal error: 'unistd.h' file not found
     8 | #include <unistd.h>
       |          ^~~~~~~~~~

Handle this by adding a new testsuite/lib/gdb_watchdog.h header that
defines a new gdb_watchdog function, which wraps alarm on Unix-like
systems, and uses a timer on Windows.

This patch adjusts gdb.base/attach.c as example of usage.  Testing
gdb.base/attach.exp with clang/x86_64-pc-windows-msvc required a
related portability tweak to can_spawn_for_attach, to not rely on
unistd.h on Windows.

gdb.rocm/mi-attach.cpp is another example adjusted, one which always
runs with clang configured as x86_64-pc-windows-msvc on Windows (via
hipcc).

Change-Id: I3b07bcb60de039d34888ef3494a5000de4471951
---
 gdb/testsuite/gdb.base/attach.c      |  4 +-
 gdb/testsuite/gdb.rocm/mi-attach.cpp |  4 +-
 gdb/testsuite/lib/gdb.exp            | 15 ++++-
 gdb/testsuite/lib/gdb_watchdog.h     | 83 ++++++++++++++++++++++++++++
 4 files changed, 101 insertions(+), 5 deletions(-)
 create mode 100644 gdb/testsuite/lib/gdb_watchdog.h

diff --git a/gdb/testsuite/gdb.base/attach.c b/gdb/testsuite/gdb.base/attach.c
index b3c54984012..41b304ef594 100644
--- a/gdb/testsuite/gdb.base/attach.c
+++ b/gdb/testsuite/gdb.base/attach.c
@@ -5,7 +5,7 @@
    exit unless/until gdb sets the variable to non-zero.)
    */
 #include <stdio.h>
-#include <unistd.h>
+#include "../lib/gdb_watchdog.h"
 
 int  bidule = 0;
 volatile int  should_exit = 0;
@@ -14,7 +14,7 @@ int main ()
 {
   int  local_i = 0;
 
-  alarm (60);
+  gdb_watchdog (60);
 
   while (! should_exit)
     {
diff --git a/gdb/testsuite/gdb.rocm/mi-attach.cpp b/gdb/testsuite/gdb.rocm/mi-attach.cpp
index da7659dc566..5752cdd10bb 100644
--- a/gdb/testsuite/gdb.rocm/mi-attach.cpp
+++ b/gdb/testsuite/gdb.rocm/mi-attach.cpp
@@ -15,8 +15,8 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-#include <unistd.h>
 #include <hip/hip_runtime.h>
+#include "../lib/gdb_watchdog.h"
 
 __global__ void
 kern ()
@@ -30,7 +30,7 @@ main ()
 {
   /* This program will run outside of GDB, make sure that if anything goes
      wrong it eventually gets killed.  */
-  alarm (30);
+  gdb_watchdog (30);
 
   kern<<<1, 1>>> ();
   return hipDeviceSynchronize () != hipSuccess;
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 98691dfce25..857d1d634c2 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -6846,7 +6846,20 @@ gdb_caching_proc can_spawn_for_attach {} {
 
     set me "can_spawn_for_attach"
     set src {
-	#include <unistd.h>
+	#ifdef _WIN32
+	# include <windows.h>
+	#else
+	# include <unistd.h>
+	#endif
+
+	#ifdef _WIN32
+	unsigned
+	sleep (unsigned seconds)
+	{
+	    Sleep (seconds * 1000);
+	    return 0;
+	}
+	#endif
 
 	int
 	main (void)
diff --git a/gdb/testsuite/lib/gdb_watchdog.h b/gdb/testsuite/lib/gdb_watchdog.h
new file mode 100644
index 00000000000..e16f6b06f38
--- /dev/null
+++ b/gdb/testsuite/lib/gdb_watchdog.h
@@ -0,0 +1,83 @@
+/* This file is part of GDB, the GNU debugger.
+
+   Copyright 2025 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Set a watchdog that aborts the testcase after a timeout.  */
+
+#ifndef GDB_WATCHDOG_H
+#define GDB_WATCHDOG_H
+
+/* Forward define to make sure the definitions have the right
+   prototype, at least in C.  */
+static void gdb_watchdog (unsigned int seconds);
+
+static const char _gdb_watchdog_msg[] = "gdb_watchdog: timeout expired - aborting test\n";
+
+#ifdef _WIN32
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+static VOID CALLBACK
+_gdb_watchdog_timer_routine (PVOID lpParam, BOOLEAN TimerOrWaitFired)
+{
+  fputs (_gdb_watchdog_msg, stderr);
+  fflush (stderr);
+  abort ();
+}
+
+static void
+gdb_watchdog (unsigned int seconds)
+{
+  HANDLE timer;
+  HANDLE timer_queue;
+
+  timer_queue = CreateTimerQueue ();
+  if (timer_queue == NULL)
+    return;
+
+  if (!CreateTimerQueueTimer (&timer, timer_queue,
+			      _gdb_watchdog_timer_routine, NULL,
+			      seconds * 1000, 0, 0))
+    {
+      /* Failed to create timer.  */
+      DeleteTimerQueue (timer_queue);
+    }
+}
+
+#else /* POSIX systems */
+
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+
+static void
+_gdb_sigalrm_handler (int signo)
+{
+  write (2, _gdb_watchdog_msg, sizeof (_gdb_watchdog_msg) - 1);
+  abort ();
+}
+
+static void
+gdb_watchdog (unsigned int seconds)
+{
+  signal (SIGALRM, _gdb_sigalrm_handler);
+  alarm (seconds);
+}
+
+#endif
+
+#endif /* GDB_WATCHDOG_H */

base-commit: f5b1b0288a97965bd71668b046fa35a85c4cea04
-- 
2.50.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] testsuite: Introduce gdb_watchdog (avoid unistd.h/alarm)
  2025-08-08 22:50 [PATCH] testsuite: Introduce gdb_watchdog (avoid unistd.h/alarm) Pedro Alves
@ 2025-08-10  3:28 ` Kevin Buettner
  2025-08-11 11:48   ` Pedro Alves
  2025-08-12 14:41 ` Tom Tromey
  1 sibling, 1 reply; 7+ messages in thread
From: Kevin Buettner @ 2025-08-10  3:28 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

Hi Pedro,

On Fri,  8 Aug 2025 23:50:50 +0100
Pedro Alves <pedro@palves.net> wrote:

> There are a good number of testcases in the testsuite that use alarm()
> as a watchdog that aborts the test if something goes wrong.
> 
> alarm()/SIG_ALRM do not exist on (native) Windows, so those tests fail
> to compile there.
> 
> For example, testing with x86_64-w64-mingw32-gcc, we see:
> 
>  Running /c/rocgdb/src/gdb/testsuite/gdb.base/attach.exp ...
>  gdb compile failed, C:/rocgdb/src/gdb/testsuite/gdb.base/attach.c: In
> function 'main': C:/rocgdb/src/gdb/testsuite/gdb.base/attach.c:17:3:
> error: implicit declaration of function 'alarm'
> [-Wimplicit-function-declaration] 17 |   alarm (60); |   ^~~~~
> 
> While testing with a clang configured to default to
> x86_64-pc-windows-msvc, which uses the C/C++ runtime headers from
> Visual Studio and has no unistd.h, we get:
> 
>  Running /c/rocgdb/src/gdb/testsuite/gdb.base/attach.exp ...
>  gdb compile failed, C:/rocgdb/src/gdb/testsuite/gdb.base/attach.c:8:10:
> fatal error: 'unistd.h' file not found 8 | #include <unistd.h>
>        |          ^~~~~~~~~~
> 
> Handle this by adding a new testsuite/lib/gdb_watchdog.h header that
> defines a new gdb_watchdog function, which wraps alarm on Unix-like
> systems, and uses a timer on Windows.
> 
> This patch adjusts gdb.base/attach.c as example of usage.  Testing
> gdb.base/attach.exp with clang/x86_64-pc-windows-msvc required a
> related portability tweak to can_spawn_for_attach, to not rely on
> unistd.h on Windows.
> 
> gdb.rocm/mi-attach.cpp is another example adjusted, one which always
> runs with clang configured as x86_64-pc-windows-msvc on Windows (via
> hipcc).

This all sounds reasonble to me.

One possible nit, and it's *way* outside my wheelhouse, so feel free to
ignore it...

[...]
> +static VOID CALLBACK
> +_gdb_watchdog_timer_routine (PVOID lpParam, BOOLEAN TimerOrWaitFired)
> +{
> +  fputs (_gdb_watchdog_msg, stderr);
> +  fflush (stderr);

On POSIX, fputs and fflush are not async-signal-safe.  It's my
understanding that they aren't on WIN32 either, but I don't know
whether this is actually a signal handler.  In any case, my AI
assistant (Qwen3 Coder) says that something like this might
work:

    DWORD bytes_written;
    WriteFile(GetStdHandle(STD_ERROR_HANDLE), _gdb_watchdog_msg, 
	      sizeof(_gdb_watchdog_msg)-1, &bytes_written, NULL);

Regardless, the rest LGTM.  And even if fputs and fflush aren't
async-signal-safe in this context, I doubt that it matters much.

So...

Approved-by: Kevin Buettner <kevinb@redhat.com>


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] testsuite: Introduce gdb_watchdog (avoid unistd.h/alarm)
  2025-08-10  3:28 ` Kevin Buettner
@ 2025-08-11 11:48   ` Pedro Alves
  0 siblings, 0 replies; 7+ messages in thread
From: Pedro Alves @ 2025-08-11 11:48 UTC (permalink / raw)
  To: Kevin Buettner; +Cc: gdb-patches

On 2025-08-10 04:28, Kevin Buettner wrote:
> Hi Pedro,

Hi!

> 
> On Fri,  8 Aug 2025 23:50:50 +0100
> This all sounds reasonble to me.
> 
> One possible nit, and it's *way* outside my wheelhouse, so feel free to
> ignore it...
> 
> [...]
>> +static VOID CALLBACK
>> +_gdb_watchdog_timer_routine (PVOID lpParam, BOOLEAN TimerOrWaitFired)
>> +{
>> +  fputs (_gdb_watchdog_msg, stderr);
>> +  fflush (stderr);
> 
> On POSIX, fputs and fflush are not async-signal-safe.  It's my
> understanding that they aren't on WIN32 either, but I don't know
> whether this is actually a signal handler.

There isn't actually a concept of async-signal-safety on Windows.  Signal
handlers don't run on the mainline code's preempted stack, like happen on POSIX.
Instead, Windows runs the signal handler on a system-created thread, concurrently
with mainline code.

In this case, we don't have a signal handler, but it's basically the same thing.
The timer runs on a separate thread (Windows thread-pool thread in this case).

So the concern here would be the same concern with any two threads calling
into fputs/fflush at the same time.  The stdio routines are thread safe, in
that they serialize access to FILE* streams with a per-stream internal lock,
so simultaneous fputs calls to the same stream from different threads won’t
corrupt the stream's buffer.

I think that the only case where a call to fputs/fflush here could block
indefinitely, is if they end up blocking inside the internal WriteFile
they do, say, because they are writing to a full pipe and the reading
end isn't consuming input.  But for that scenario, going directly to
WriteFile won't help either, it will block the same way.

This is exactly the same for the write call on the POSIX side, BTW.

I think the only way to avoid this would be if we tried to open the
handle with FILE_FLAG_OVERLAPPED and do async writes, but that adds
complexity and the watchdog thread must pump the overlapped completion
or timeout logic.  Similarly, on the POSIX side we'd have to make sure to
do an async write.

Or we could just not print anything.

abort() is a CRT function too, and it flushes streams (hmm, maybe I don't need
the fflush after all), and if we were to avoid fputs/fflush to avoid locks, then
I'd think that we would want to avoid abort too.  Maybe call
ExitProcess or TerminateProcess directly?

However, I was thinking that using abort() could be nice for leaving it open the possibility
making Windows generate a minidump or for hooking Windows's crash reporting mechanism with
cygwin's dumper to generate an ELF core dump if we wanted, or something of the sort.
I suppose we could still have that if we terminate the process with something at
the Win32 level that triggers the same mechanisms, like maybe raise an uncaught exception?

Dunno.  fputs + abort just seems appealing to me for being simple, and abort() being the
same that we do on the POSIX side.

And in the end I think it's like you say -- I doubt it matters much.

> 
> Regardless, the rest LGTM.  And even if fputs and fflush aren't
> async-signal-safe in this context, I doubt that it matters much.
> 
> So...
> 
> Approved-by: Kevin Buettner <kevinb@redhat.com>
> 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] testsuite: Introduce gdb_watchdog (avoid unistd.h/alarm)
  2025-08-08 22:50 [PATCH] testsuite: Introduce gdb_watchdog (avoid unistd.h/alarm) Pedro Alves
  2025-08-10  3:28 ` Kevin Buettner
@ 2025-08-12 14:41 ` Tom Tromey
  2025-08-12 18:57   ` Pedro Alves
  1 sibling, 1 reply; 7+ messages in thread
From: Tom Tromey @ 2025-08-12 14:41 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

>>>>> "Pedro" == Pedro Alves <pedro@palves.net> writes:

Pedro> Handle this by adding a new testsuite/lib/gdb_watchdog.h header that
Pedro> defines a new gdb_watchdog function, which wraps alarm on Unix-like
Pedro> systems, and uses a timer on Windows.

It seems like this would need some special work to handle the remote
host testing case.

Pedro> +#include "../lib/gdb_watchdog.h"
 
... at least, I assume this isn't automatically copied to the remote.

Tom

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] testsuite: Introduce gdb_watchdog (avoid unistd.h/alarm)
  2025-08-12 14:41 ` Tom Tromey
@ 2025-08-12 18:57   ` Pedro Alves
  2025-08-13  0:51     ` [PATCH v2] " Pedro Alves
  0 siblings, 1 reply; 7+ messages in thread
From: Pedro Alves @ 2025-08-12 18:57 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

On 2025-08-12 15:41, Tom Tromey wrote:
>>>>>> "Pedro" == Pedro Alves <pedro@palves.net> writes:
> 
> Pedro> Handle this by adding a new testsuite/lib/gdb_watchdog.h header that
> Pedro> defines a new gdb_watchdog function, which wraps alarm on Unix-like
> Pedro> systems, and uses a timer on Windows.
> 
> It seems like this would need some special work to handle the remote
> host testing case.
> 
> Pedro> +#include "../lib/gdb_watchdog.h"
>  
> ... at least, I assume this isn't automatically copied to the remote.
> 

Hmm.  Yeah, I forget it's also possible to compile on the host side.

I see that for example lib/attributes.h is handled with lappend_include_file
and include_file.  I'll take a better look.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v2] testsuite: Introduce gdb_watchdog (avoid unistd.h/alarm)
  2025-08-12 18:57   ` Pedro Alves
@ 2025-08-13  0:51     ` Pedro Alves
  2025-08-22 19:08       ` Pedro Alves
  0 siblings, 1 reply; 7+ messages in thread
From: Pedro Alves @ 2025-08-13  0:51 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

On 2025-08-12 19:57, Pedro Alves wrote:
> On 2025-08-12 15:41, Tom Tromey wrote:
>>>>>>> "Pedro" == Pedro Alves <pedro@palves.net> writes:
>>
>> Pedro> Handle this by adding a new testsuite/lib/gdb_watchdog.h header that
>> Pedro> defines a new gdb_watchdog function, which wraps alarm on Unix-like
>> Pedro> systems, and uses a timer on Windows.
>>
>> It seems like this would need some special work to handle the remote
>> host testing case.
>>
>> Pedro> +#include "../lib/gdb_watchdog.h"
>>  
>> ... at least, I assume this isn't automatically copied to the remote.
>>
> 
> Hmm.  Yeah, I forget it's also possible to compile on the host side.
> 
> I see that for example lib/attributes.h is handled with lappend_include_file
> and include_file.  I'll take a better look.


So locally I have patches touching a lot more testcases, converting them to use
gdb_watchdog.  I adjusted them all locally to use lappend_include_file, but
I didn't like the result all that much.  It's annoying to have to list the
includes twice, once in the source files, and once in the .exp file.

Even worst is that in my local series, I have a patch that makes
gdb_watchdog.h include another header in testsuite/lib/, and the lappend_include_file
approach would mean that every .exp file that includes gdb_watchdog.h would need
to be updated to also lappend_include_file the header that gdb_watchdog.h includes.

So I thought about making this automatic, and came up with this:

 [PATCH] Automatically handle includes in testsuite/lib/
 https://inbox.sourceware.org/gdb-patches/20250813004100.2525141-1-pedro@palves.net/T/#u

Let me know what you think.

With that in place, the updated gdb_watchdog patch is below.  The only difference
is that we now include gdb_watchdog.h like so:

 #include "gdb_watchdog.h"

instead of:

 #include "../lib/gdb_watchdog.h"

From 338f5c87ccea20cfe65b122d227ee37499b04c6f Mon Sep 17 00:00:00 2001
From: Pedro Alves <pedro@palves.net>
Date: Fri, 8 Aug 2025 23:50:04 +0100
Subject: [PATCH v2] testsuite: Introduce gdb_watchdog (avoid unistd.h/alarm)

There are a good number of testcases in the testsuite that use alarm()
as a watchdog that aborts the test if something goes wrong.

alarm()/SIG_ALRM do not exist on (native) Windows, so those tests fail
to compile there.

For example, testing with x86_64-w64-mingw32-gcc, we see:

 Running /c/rocgdb/src/gdb/testsuite/gdb.base/attach.exp ...
 gdb compile failed, C:/rocgdb/src/gdb/testsuite/gdb.base/attach.c: In function 'main':
 C:/rocgdb/src/gdb/testsuite/gdb.base/attach.c:17:3: error: implicit declaration of function 'alarm' [-Wimplicit-function-declaration]
    17 |   alarm (60);
       |   ^~~~~

While testing with a clang configured to default to
x86_64-pc-windows-msvc, which uses the C/C++ runtime headers from
Visual Studio and has no unistd.h, we get:

 Running /c/rocgdb/src/gdb/testsuite/gdb.base/attach.exp ...
 gdb compile failed, C:/rocgdb/src/gdb/testsuite/gdb.base/attach.c:8:10: fatal error: 'unistd.h' file not found
     8 | #include <unistd.h>
       |          ^~~~~~~~~~

Handle this by adding a new testsuite/lib/gdb_watchdog.h header that
defines a new gdb_watchdog function, which wraps alarm on Unix-like
systems, and uses a timer on Windows.

This patch adjusts gdb.base/attach.c as example of usage.  Testing
gdb.base/attach.exp with clang/x86_64-pc-windows-msvc required a
related portability tweak to can_spawn_for_attach, to not rely on
unistd.h on Windows.

gdb.rocm/mi-attach.cpp is another example adjusted, one which always
runs with clang configured as x86_64-pc-windows-msvc on Windows (via
hipcc).

Change-Id: I3b07bcb60de039d34888ef3494a5000de4471951
---
 gdb/testsuite/gdb.base/attach.c      |  4 +-
 gdb/testsuite/gdb.rocm/mi-attach.cpp |  4 +-
 gdb/testsuite/lib/gdb.exp            | 15 +++++-
 gdb/testsuite/lib/gdb_watchdog.h     | 78 ++++++++++++++++++++++++++++
 4 files changed, 96 insertions(+), 5 deletions(-)
 create mode 100644 gdb/testsuite/lib/gdb_watchdog.h

diff --git a/gdb/testsuite/gdb.base/attach.c b/gdb/testsuite/gdb.base/attach.c
index b3c54984012..5133dd07e55 100644
--- a/gdb/testsuite/gdb.base/attach.c
+++ b/gdb/testsuite/gdb.base/attach.c
@@ -5,7 +5,7 @@
    exit unless/until gdb sets the variable to non-zero.)
    */
 #include <stdio.h>
-#include <unistd.h>
+#include "gdb_watchdog.h"
 
 int  bidule = 0;
 volatile int  should_exit = 0;
@@ -14,7 +14,7 @@ int main ()
 {
   int  local_i = 0;
 
-  alarm (60);
+  gdb_watchdog (60);
 
   while (! should_exit)
     {
diff --git a/gdb/testsuite/gdb.rocm/mi-attach.cpp b/gdb/testsuite/gdb.rocm/mi-attach.cpp
index da7659dc566..441d460146a 100644
--- a/gdb/testsuite/gdb.rocm/mi-attach.cpp
+++ b/gdb/testsuite/gdb.rocm/mi-attach.cpp
@@ -15,8 +15,8 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-#include <unistd.h>
 #include <hip/hip_runtime.h>
+#include "gdb_watchdog.h"
 
 __global__ void
 kern ()
@@ -30,7 +30,7 @@ main ()
 {
   /* This program will run outside of GDB, make sure that if anything goes
      wrong it eventually gets killed.  */
-  alarm (30);
+  gdb_watchdog (30);
 
   kern<<<1, 1>>> ();
   return hipDeviceSynchronize () != hipSuccess;
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 0361f10b9a6..d989314c28d 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -6849,7 +6849,20 @@ gdb_caching_proc can_spawn_for_attach {} {
 
     set me "can_spawn_for_attach"
     set src {
-	#include <unistd.h>
+	#ifdef _WIN32
+	# include <windows.h>
+	#else
+	# include <unistd.h>
+	#endif
+
+	#ifdef _WIN32
+	unsigned
+	sleep (unsigned seconds)
+	{
+	    Sleep (seconds * 1000);
+	    return 0;
+	}
+	#endif
 
 	int
 	main (void)
diff --git a/gdb/testsuite/lib/gdb_watchdog.h b/gdb/testsuite/lib/gdb_watchdog.h
new file mode 100644
index 00000000000..459b958836e
--- /dev/null
+++ b/gdb/testsuite/lib/gdb_watchdog.h
@@ -0,0 +1,78 @@
+/* This file is part of GDB, the GNU debugger.
+
+   Copyright 2025 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Set a watchdog that aborts the testcase after a timeout.  */
+
+#ifndef GDB_WATCHDOG_H
+#define GDB_WATCHDOG_H
+
+/* Forward define to make sure the definitions have the right
+   prototype, at least in C.  */
+static void gdb_watchdog (unsigned int seconds);
+
+static const char _gdb_watchdog_msg[]
+  = "gdb_watchdog: timeout expired - aborting test\n";
+
+#ifdef _WIN32
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+static VOID CALLBACK
+_gdb_watchdog_timer_routine (PVOID lpParam, BOOLEAN TimerOrWaitFired)
+{
+  fputs (_gdb_watchdog_msg, stderr);
+  abort ();
+}
+
+static void
+gdb_watchdog (unsigned int seconds)
+{
+  HANDLE timer;
+
+  if (!CreateTimerQueueTimer (&timer, NULL,
+			      _gdb_watchdog_timer_routine, NULL,
+			      seconds * 1000, 0, 0))
+    {
+      /* Failed to create timer.  */
+      DeleteTimerQueue (timer_queue);
+    }
+}
+
+#else /* POSIX systems */
+
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+
+static void
+_gdb_sigalrm_handler (int signo)
+{
+  write (2, _gdb_watchdog_msg, sizeof (_gdb_watchdog_msg) - 1);
+  abort ();
+}
+
+static void
+gdb_watchdog (unsigned int seconds)
+{
+  signal (SIGALRM, _gdb_sigalrm_handler);
+  alarm (seconds);
+}
+
+#endif
+
+#endif /* GDB_WATCHDOG_H */

base-commit: f5b1b0288a97965bd71668b046fa35a85c4cea04
prerequisite-patch-id: 9b579e19acdb2121d8232cafc1bb63ef881684eb
-- 
2.50.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2] testsuite: Introduce gdb_watchdog (avoid unistd.h/alarm)
  2025-08-13  0:51     ` [PATCH v2] " Pedro Alves
@ 2025-08-22 19:08       ` Pedro Alves
  0 siblings, 0 replies; 7+ messages in thread
From: Pedro Alves @ 2025-08-22 19:08 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

On 2025-08-13 01:51, Pedro Alves wrote:
> On 2025-08-12 19:57, Pedro Alves wrote:
>> On 2025-08-12 15:41, Tom Tromey wrote:
>>>>>>>> "Pedro" == Pedro Alves <pedro@palves.net> writes:
>>>
>>> Pedro> Handle this by adding a new testsuite/lib/gdb_watchdog.h header that
>>> Pedro> defines a new gdb_watchdog function, which wraps alarm on Unix-like
>>> Pedro> systems, and uses a timer on Windows.
>>>
>>> It seems like this would need some special work to handle the remote
>>> host testing case.
>>>
>>> Pedro> +#include "../lib/gdb_watchdog.h"
>>>  
>>> ... at least, I assume this isn't automatically copied to the remote.
>>>
>>
>> Hmm.  Yeah, I forget it's also possible to compile on the host side.
>>
>> I see that for example lib/attributes.h is handled with lappend_include_file
>> and include_file.  I'll take a better look.
> 
> 
> So locally I have patches touching a lot more testcases, converting them to use
> gdb_watchdog.  I adjusted them all locally to use lappend_include_file, but
> I didn't like the result all that much.  It's annoying to have to list the
> includes twice, once in the source files, and once in the .exp file.
> 
> Even worst is that in my local series, I have a patch that makes
> gdb_watchdog.h include another header in testsuite/lib/, and the lappend_include_file
> approach would mean that every .exp file that includes gdb_watchdog.h would need
> to be updated to also lappend_include_file the header that gdb_watchdog.h includes.
> 
> So I thought about making this automatic, and came up with this:
> 
>  [PATCH] Automatically handle includes in testsuite/lib/
>  https://inbox.sourceware.org/gdb-patches/20250813004100.2525141-1-pedro@palves.net/T/#u
> 
> Let me know what you think.
> 
> With that in place, the updated gdb_watchdog patch is below.  The only difference
> is that we now include gdb_watchdog.h like so:
> 
>  #include "gdb_watchdog.h"
> 
> instead of:
> 
>  #include "../lib/gdb_watchdog.h"
> 

FYI, I've now pushed this.  But after pushing I noticed that this v2 patch email doesn't appear
to have reached the mailing list?  I can't find it in the archives, and have gotten a copy
via the list.  Odd.

Here's what I pushed.  The v2 version that I sent before had an incomplete change in the
Windows version of gdb_watchdog.  I had noticed that it's not necessary to create
a timer queue, there's a default one, and switched to doing that in v2 (passing NULL as
timer queue to CreateTimerQueueTimer), but had forgotten to delete the DeleteTimerQueue
line.

In this version, I'm simply aborting immediately if creating the timer fails.  I don't
expect that that will ever be reached, and the idea of aborting is that if it ever is
reached, it's better to see the problem immediately so we can better understand how it
can happen, instead of silently failing to have a watchdog in place.

I have some follow up patches making use of gdb_watchdog in other tests.

Pedro Alves

From e771abf8ff88a5d98b8960a7ea49708b9ec42521 Mon Sep 17 00:00:00 2001
From: Pedro Alves <pedro@palves.net>
Date: Fri, 8 Aug 2025 23:50:04 +0100
Subject: [PATCH] testsuite: Introduce gdb_watchdog (avoid unistd.h/alarm)

There are a good number of testcases in the testsuite that use alarm()
as a watchdog that aborts the test if something goes wrong.

alarm()/SIG_ALRM do not exist on (native) Windows, so those tests fail
to compile there.

For example, testing with x86_64-w64-mingw32-gcc, we see:

 Running /c/rocgdb/src/gdb/testsuite/gdb.base/attach.exp ...
 gdb compile failed, C:/rocgdb/src/gdb/testsuite/gdb.base/attach.c: In function 'main':
 C:/rocgdb/src/gdb/testsuite/gdb.base/attach.c:17:3: error: implicit declaration of function 'alarm' [-Wimplicit-function-declaration]
    17 |   alarm (60);
       |   ^~~~~

While testing with a clang configured to default to
x86_64-pc-windows-msvc, which uses the C/C++ runtime headers from
Visual Studio and has no unistd.h, we get:

 Running /c/rocgdb/src/gdb/testsuite/gdb.base/attach.exp ...
 gdb compile failed, C:/rocgdb/src/gdb/testsuite/gdb.base/attach.c:8:10: fatal error: 'unistd.h' file not found
     8 | #include <unistd.h>
       |          ^~~~~~~~~~

Handle this by adding a new testsuite/lib/gdb_watchdog.h header that
defines a new gdb_watchdog function, which wraps alarm on Unix-like
systems, and uses a timer on Windows.

This patch adjusts gdb.base/attach.c as example of usage.  Testing
gdb.base/attach.exp with clang/x86_64-pc-windows-msvc required a
related portability tweak to can_spawn_for_attach, to not rely on
unistd.h on Windows.

gdb.rocm/mi-attach.cpp is another example adjusted, one which always
runs with clang configured as x86_64-pc-windows-msvc on Windows (via
hipcc).

Approved-by: Kevin Buettner <kevinb@redhat.com>
Change-Id: I3b07bcb60de039d34888ef3494a5000de4471951
---
 gdb/testsuite/gdb.base/attach.c      |  4 +-
 gdb/testsuite/gdb.rocm/mi-attach.cpp |  4 +-
 gdb/testsuite/lib/gdb.exp            | 15 +++++-
 gdb/testsuite/lib/gdb_watchdog.h     | 75 ++++++++++++++++++++++++++++
 4 files changed, 93 insertions(+), 5 deletions(-)
 create mode 100644 gdb/testsuite/lib/gdb_watchdog.h

diff --git a/gdb/testsuite/gdb.base/attach.c b/gdb/testsuite/gdb.base/attach.c
index b3c54984012..5133dd07e55 100644
--- a/gdb/testsuite/gdb.base/attach.c
+++ b/gdb/testsuite/gdb.base/attach.c
@@ -5,7 +5,7 @@
    exit unless/until gdb sets the variable to non-zero.)
    */
 #include <stdio.h>
-#include <unistd.h>
+#include "gdb_watchdog.h"
 
 int  bidule = 0;
 volatile int  should_exit = 0;
@@ -14,7 +14,7 @@ int main ()
 {
   int  local_i = 0;
 
-  alarm (60);
+  gdb_watchdog (60);
 
   while (! should_exit)
     {
diff --git a/gdb/testsuite/gdb.rocm/mi-attach.cpp b/gdb/testsuite/gdb.rocm/mi-attach.cpp
index da7659dc566..441d460146a 100644
--- a/gdb/testsuite/gdb.rocm/mi-attach.cpp
+++ b/gdb/testsuite/gdb.rocm/mi-attach.cpp
@@ -15,8 +15,8 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-#include <unistd.h>
 #include <hip/hip_runtime.h>
+#include "gdb_watchdog.h"
 
 __global__ void
 kern ()
@@ -30,7 +30,7 @@ main ()
 {
   /* This program will run outside of GDB, make sure that if anything goes
      wrong it eventually gets killed.  */
-  alarm (30);
+  gdb_watchdog (30);
 
   kern<<<1, 1>>> ();
   return hipDeviceSynchronize () != hipSuccess;
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 0361f10b9a6..d989314c28d 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -6849,7 +6849,20 @@ gdb_caching_proc can_spawn_for_attach {} {
 
     set me "can_spawn_for_attach"
     set src {
-	#include <unistd.h>
+	#ifdef _WIN32
+	# include <windows.h>
+	#else
+	# include <unistd.h>
+	#endif
+
+	#ifdef _WIN32
+	unsigned
+	sleep (unsigned seconds)
+	{
+	    Sleep (seconds * 1000);
+	    return 0;
+	}
+	#endif
 
 	int
 	main (void)
diff --git a/gdb/testsuite/lib/gdb_watchdog.h b/gdb/testsuite/lib/gdb_watchdog.h
new file mode 100644
index 00000000000..15d63e76198
--- /dev/null
+++ b/gdb/testsuite/lib/gdb_watchdog.h
@@ -0,0 +1,75 @@
+/* This file is part of GDB, the GNU debugger.
+
+   Copyright 2025 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Set a watchdog that aborts the testcase after a timeout.  */
+
+#ifndef GDB_WATCHDOG_H
+#define GDB_WATCHDOG_H
+
+/* Forward declaration to make sure the definitions have the right
+   prototype, at least in C.  */
+static void gdb_watchdog (unsigned int seconds);
+
+static const char _gdb_watchdog_msg[]
+  = "gdb_watchdog: timeout expired - aborting test\n";
+
+#ifdef _WIN32
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+static VOID CALLBACK
+_gdb_watchdog_timer_routine (PVOID lpParam, BOOLEAN TimerOrWaitFired)
+{
+  fputs (_gdb_watchdog_msg, stderr);
+  abort ();
+}
+
+static void
+gdb_watchdog (unsigned int seconds)
+{
+  HANDLE timer;
+
+  if (!CreateTimerQueueTimer (&timer, NULL,
+			      _gdb_watchdog_timer_routine, NULL,
+			      seconds * 1000, 0, 0))
+    abort ();
+}
+
+#else /* POSIX systems */
+
+#include <unistd.h>
+#include <signal.h>
+#include <stdlib.h>
+
+static void
+_gdb_sigalrm_handler (int signo)
+{
+  write (2, _gdb_watchdog_msg, sizeof (_gdb_watchdog_msg) - 1);
+  abort ();
+}
+
+static void
+gdb_watchdog (unsigned int seconds)
+{
+  signal (SIGALRM, _gdb_sigalrm_handler);
+  alarm (seconds);
+}
+
+#endif
+
+#endif /* GDB_WATCHDOG_H */

base-commit: 3214cb0ce58245516d35cd93887f0d3bc14b5ebf
-- 
2.50.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2025-08-22 19:09 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-08-08 22:50 [PATCH] testsuite: Introduce gdb_watchdog (avoid unistd.h/alarm) Pedro Alves
2025-08-10  3:28 ` Kevin Buettner
2025-08-11 11:48   ` Pedro Alves
2025-08-12 14:41 ` Tom Tromey
2025-08-12 18:57   ` Pedro Alves
2025-08-13  0:51     ` [PATCH v2] " Pedro Alves
2025-08-22 19:08       ` Pedro Alves

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox