[2/3] gdb/python: break more dependencies between gdbpy_initialize_* functions

Message ID 1e89f7f71a8170a1529697d1bfc9d971d89978f9.1664729134.git.aburgess@redhat.com
State Committed
Commit 8a3b17063e86ba7687896de7b5de870006a02ef5
Headers
Series New mechanism to initialise Python components in GDB |

Commit Message

Andrew Burgess Oct. 2, 2022, 4:53 p.m. UTC
  In a later commit in this series I will propose removing all of the
explicit gdbpy_initialize_* calls from python.c and replace these
calls with a more generic mechanism.

One of the side effects of this generic mechanism is that the order in
which the various Python sub-systems within GDB are initialized is no
longer guaranteed.

On the whole I don't think this matters, most of the sub-systems are
independent of each other, though testing did reveal a few places
where we did have dependencies, though I don't think those
dependencies were explicitly documented in comment anywhere.

This commit is similar to the previous one, and fixes the second
dependency issue that I found.

In this case the finish_breakpoint_object_type uses the
breakpoint_object_type as its tp_base, this means that
breakpoint_object_type must have been initialized with a call to
PyType_Ready before finish_breakpoint_object_type can be initialized.

Previously we depended on the ordering of calls to
gdbpy_initialize_breakpoints and gdbpy_initialize_finishbreakpoints in
python.c.

After this commit a new function gdbpy_breakpoint_init_breakpoint_type
exists, this function ensures that breakpoint_object_type has been
initialized, and can be called from any gdbpy_initialize_* function.

I feel that this change makes the dependency explicit, which I think
is a good thing.

There should be no user visible changes after this commit.
---
 gdb/python/py-breakpoint.c       | 23 +++++++++++++++++++++--
 gdb/python/py-finishbreakpoint.c |  3 +++
 gdb/python/python-internal.h     | 12 ++++++++++++
 3 files changed, 36 insertions(+), 2 deletions(-)
  

Comments

Tom Tromey Oct. 14, 2022, 5:06 p.m. UTC | #1
>>>>> "Andrew" == Andrew Burgess via Gdb-patches <gdb-patches@sourceware.org> writes:

Andrew> After this commit a new function gdbpy_breakpoint_init_breakpoint_type
Andrew> exists, this function ensures that breakpoint_object_type has been
Andrew> initialized, and can be called from any gdbpy_initialize_* function.

Andrew> I feel that this change makes the dependency explicit, which I think
Andrew> is a good thing.

Me too.  Thanks for doing this, I think you should check it in.

Tom
  
Andrew Burgess Oct. 20, 2022, 3:59 p.m. UTC | #2
Tom Tromey <tom@tromey.com> writes:

>>>>>> "Andrew" == Andrew Burgess via Gdb-patches <gdb-patches@sourceware.org> writes:
>
> Andrew> After this commit a new function gdbpy_breakpoint_init_breakpoint_type
> Andrew> exists, this function ensures that breakpoint_object_type has been
> Andrew> initialized, and can be called from any gdbpy_initialize_* function.
>
> Andrew> I feel that this change makes the dependency explicit, which I think
> Andrew> is a good thing.
>
> Me too.  Thanks for doing this, I think you should check it in.

I've pushed this patch, and will have a think about what to do with
patch 3/3.

Thanks,
Andrew
  

Patch

diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
index dd4519a1b05..7a757432948 100644
--- a/gdb/python/py-breakpoint.c
+++ b/gdb/python/py-breakpoint.c
@@ -989,6 +989,26 @@  build_bp_list (struct breakpoint *b, PyObject *list)
   return PyList_Append (list, bp) == 0;
 }
 
+/* See python-internal.h.  */
+
+bool
+gdbpy_breakpoint_init_breakpoint_type ()
+{
+  if (breakpoint_object_type.tp_new == nullptr)
+    {
+      breakpoint_object_type.tp_new = PyType_GenericNew;
+      if (PyType_Ready (&breakpoint_object_type) < 0)
+	{
+	  /* Reset tp_new back to nullptr so future calls to this function
+	     will try calling PyType_Ready again.  */
+	  breakpoint_object_type.tp_new = nullptr;
+	  return false;
+	}
+    }
+
+  return true;
+}
+
 /* Static function to return a tuple holding all breakpoints.  */
 
 PyObject *
@@ -1216,8 +1236,7 @@  gdbpy_initialize_breakpoints (void)
 {
   int i;
 
-  breakpoint_object_type.tp_new = PyType_GenericNew;
-  if (PyType_Ready (&breakpoint_object_type) < 0)
+  if (!gdbpy_breakpoint_init_breakpoint_type ())
     return -1;
 
   if (gdb_pymodule_addobject (gdb_module, "Breakpoint",
diff --git a/gdb/python/py-finishbreakpoint.c b/gdb/python/py-finishbreakpoint.c
index c4b043f5bfe..67637f16a39 100644
--- a/gdb/python/py-finishbreakpoint.c
+++ b/gdb/python/py-finishbreakpoint.c
@@ -408,6 +408,9 @@  bpfinishpy_handle_exit (struct inferior *inf)
 int
 gdbpy_initialize_finishbreakpoints (void)
 {
+  if (!gdbpy_breakpoint_init_breakpoint_type ())
+    return -1;
+
   if (PyType_Ready (&finish_breakpoint_object_type) < 0)
     return -1;
 
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index d624b23fdc5..a4f54e78268 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -290,6 +290,18 @@  extern PyTypeObject frame_object_type
 extern PyTypeObject thread_object_type
     CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("thread_object");
 
+/* Ensure that breakpoint_object_type is initialized and return true.  If
+   breakpoint_object_type can't be initialized then set a suitable Python
+   error and return false.
+
+   This function needs to be called from any gdbpy_initialize_* function
+   that wants to reference breakpoint_object_type.  After all the
+   gdbpy_initialize_* functions have been called then breakpoint_object_type
+   is guaranteed to have been initialized, and this function does not need
+   calling before referencing breakpoint_object_type.  */
+
+extern bool gdbpy_breakpoint_init_breakpoint_type ();
+
 struct gdbpy_breakpoint_object
 {
   PyObject_HEAD