+2017-09-11 Tom Tromey <tom@tromey.com>
+
+ PR python/15622:
+ * NEWS: Add entry.
+ * python/python.c (do_start_initialization): Initialize new event
+ types.
+ * python/python-internal.h (gdbpy_initialize_new_inferior_event)
+ (gdbpy_initialize_inferior_deleted_event)
+ (gdbpy_initialize_new_thread_event): Declare.
+ * python/py-threadevent.c (create_thread_event_object): Add option
+ "thread" parameter.
+ * python/py-inferior.c (new_thread_event_object_type)
+ (new_inferior_event_object_type)
+ (inferior_deleted_event_object_type): Declare.
+ (python_new_inferior, python_inferior_deleted): New functions.
+ (add_thread_object): Emit new_thread event.
+ (gdbpy_initialize_inferior): Attach new functions to corresponding
+ observers.
+ (new_thread, new_inferior, inferior_deleted): Define new event
+ types.
+ * python/py-evts.c (gdbpy_initialize_py_events): Add new
+ registries.
+ * python/py-events.h (events_object) <new_inferior,
+ inferior_deleted, new_thread>: New fields.
+ * python/py-event.h (create_thread_event_breakpoint): Add optional
+ "thread" parameter.
+
2017-09-10 Andrew Burgess <andrew.burgess@embecosm.com>
* utils.c (abort_with_message): Don't compare gdb_stderr to NULL,
the remote inferior is started by the GDBserver, use the "unset
environment" command.
+* Python Scripting
+
+ ** New events gdb.new_inferior, gdb.inferior_deleted, and
+ gdb.new_thread are emitted. See the manual for further
+ description of these.
+
* New features in the GDB remote stub, GDBserver
** New "--selftest" command line option runs some GDBserver self
+2017-09-11 Tom Tromey <tom@tromey.com>
+
+ * python.texi (Events In Python): Document new events.
+
2017-09-04 Pedro Alves <palves@redhat.com>
* gdb.texinfo (Variables) <Program Variables>: Document inspecting
This event carries no payload. It is emitted each time @value{GDBN}
presents a prompt to the user.
+@item events.new_inferior
+This is emitted when a new inferior is created. Note that the
+inferior is not necessarily running; in fact, it may not even have an
+associated executable.
+
+The event is of type @code{gdb.NewInferiorEvent}. This has a single
+attribute:
+
+@defvar NewInferiorEvent.inferior
+The new inferior, a @code{gdb.Inferior} object.
+@end defvar
+
+@item events.inferior_deleted
+This is emitted when an inferior has been deleted. Note that this is
+not the same as process exit; it is notified when the inferior itself
+is removed, say via @code{remove-inferiors}.
+
+The event is of type @code{gdb.InferiorDeletedEvent}. This has a single
+attribute:
+
+@defvar NewInferiorEvent.inferior
+The inferior that is being removed, a @code{gdb.Inferior} object.
+@end defvar
+
+@item events.new_thread
+This is emitted when @value{GDBN} notices a new thread. The event is of
+type @code{gdb.NewThreadEvent}, which extends @code{gdb.ThreadEvent}.
+This has a single attribute:
+
+@defvar NewThreadEvent.inferior_thread
+The new thread.
+@end defvar
+
@end table
@node Threads In Python
eventregistry_object *registry);
extern PyObject *create_event_object (PyTypeObject *py_type);
-extern PyObject *create_thread_event_object (PyTypeObject *py_type);
+extern PyObject *create_thread_event_object (PyTypeObject *py_type,
+ PyObject *thread = nullptr);
extern int emit_new_objfile_event (struct objfile *objfile);
extern int emit_clear_objfiles_event (void);
eventregistry_object *exited;
eventregistry_object *new_objfile;
eventregistry_object *clear_objfiles;
+ eventregistry_object *new_inferior;
+ eventregistry_object *inferior_deleted;
+ eventregistry_object *new_thread;
eventregistry_object *inferior_call;
eventregistry_object *memory_changed;
eventregistry_object *register_changed;
if (add_new_registry (&gdb_py_events.clear_objfiles, "clear_objfiles") < 0)
return -1;
+ if (add_new_registry (&gdb_py_events.new_inferior, "new_inferior") < 0)
+ return -1;
+
+ if (add_new_registry (&gdb_py_events.inferior_deleted, "inferior_deleted") < 0)
+ return -1;
+
+ if (add_new_registry (&gdb_py_events.new_thread, "new_thread") < 0)
+ return -1;
+
if (add_new_registry (&gdb_py_events.breakpoint_created,
"breakpoint_created") < 0)
return -1;
#include "py-event.h"
#include "py-stopevent.h"
+extern PyTypeObject new_thread_event_object_type
+ CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("event_object");
+extern PyTypeObject new_inferior_event_object_type
+ CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("event_object");
+extern PyTypeObject inferior_deleted_event_object_type
+ CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("event_object");
+
struct threadlist_entry {
thread_object *thread_obj;
struct threadlist_entry *next;
return (PyObject *) inf_obj;
}
+/* Called when a new inferior is created. Notifies any Python event
+ listeners. */
+static void
+python_new_inferior (struct inferior *inf)
+{
+ if (!gdb_python_initialized)
+ return;
+
+ gdbpy_enter enter_py (python_gdbarch, python_language);
+
+ if (evregpy_no_listeners_p (gdb_py_events.new_inferior))
+ return;
+
+ gdbpy_ref<> inf_obj (inferior_to_inferior_object (inf));
+ if (inf_obj == NULL)
+ {
+ gdbpy_print_stack ();
+ return;
+ }
+
+ gdbpy_ref<> event (create_event_object (&new_inferior_event_object_type));
+ if (event == NULL
+ || evpy_add_attribute (event.get (), "inferior", inf_obj.get ()) < 0
+ || evpy_emit_event (event.get (), gdb_py_events.new_inferior) < 0)
+ gdbpy_print_stack ();
+}
+
+/* Called when an inferior is removed. Notifies any Python event
+ listeners. */
+static void
+python_inferior_deleted (struct inferior *inf)
+{
+ if (!gdb_python_initialized)
+ return;
+
+ gdbpy_enter enter_py (python_gdbarch, python_language);
+
+ if (evregpy_no_listeners_p (gdb_py_events.inferior_deleted))
+ return;
+
+ gdbpy_ref<> inf_obj (inferior_to_inferior_object (inf));
+ if (inf_obj == NULL)
+ {
+ gdbpy_print_stack ();
+ return;
+ }
+
+ gdbpy_ref<> event (create_event_object (&inferior_deleted_event_object_type));
+ if (event == NULL
+ || evpy_add_attribute (event.get (), "inferior", inf_obj.get ()) < 0
+ || evpy_emit_event (event.get (), gdb_py_events.inferior_deleted) < 0)
+ gdbpy_print_stack ();
+}
+
/* Finds the Python Inferior object for the given PID. Returns a
reference, or NULL if PID does not match any inferior object. */
inf_obj->threads = entry;
inf_obj->nthreads++;
+
+ if (evregpy_no_listeners_p (gdb_py_events.new_thread))
+ return;
+
+ gdbpy_ref<> event (create_thread_event_object (&new_thread_event_object_type,
+ (PyObject *) thread_obj));
+ if (event == NULL
+ || evpy_emit_event (event.get (), gdb_py_events.new_thread) < 0)
+ gdbpy_print_stack ();
}
static void
observer_attach_register_changed (python_on_register_change);
observer_attach_inferior_exit (python_inferior_exit);
observer_attach_new_objfile (python_new_objfile);
+ observer_attach_inferior_added (python_new_inferior);
+ observer_attach_inferior_removed (python_inferior_deleted);
membuf_object_type.tp_new = PyType_GenericNew;
if (PyType_Ready (&membuf_object_type) < 0)
0, /* tp_init */
0, /* tp_alloc */
};
+
+GDBPY_NEW_EVENT_TYPE (new_thread,
+ "gdb.NewThreadEvent",
+ "NewThreadEvent",
+ "GDB new thread event object",
+ thread_event_object_type);
+GDBPY_NEW_EVENT_TYPE (new_inferior,
+ "gdb.NewInferiorEvent",
+ "NewInferiorEvent",
+ "GDB new inferior event object",
+ event_object_type);
+GDBPY_NEW_EVENT_TYPE (inferior_deleted,
+ "gdb.InferiorDeletedEvent",
+ "InferiorDeletedEvent",
+ "GDB inferior deleted event object",
+ event_object_type);
}
PyObject *
-create_thread_event_object (PyTypeObject *py_type)
+create_thread_event_object (PyTypeObject *py_type, PyObject *thread)
{
- PyObject *thread = NULL;
-
gdbpy_ref<> thread_event_obj (create_event_object (py_type));
if (thread_event_obj == NULL)
return NULL;
- thread = get_event_thread ();
- if (!thread)
- return NULL;
+ if (thread == NULL)
+ {
+ thread = get_event_thread ();
+ if (!thread)
+ return NULL;
+ }
if (evpy_add_attribute (thread_event_obj.get (),
"inferior_thread",
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
int gdbpy_initialize_clear_objfiles_event (void)
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+int gdbpy_initialize_new_inferior_event (void)
+ CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+int gdbpy_initialize_inferior_deleted_event (void)
+ CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+int gdbpy_initialize_new_thread_event (void)
+ CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
int gdbpy_initialize_arch (void)
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
int gdbpy_initialize_xmethods (void)
|| gdbpy_initialize_thread_event () < 0
|| gdbpy_initialize_new_objfile_event () < 0
|| gdbpy_initialize_clear_objfiles_event () < 0
+ || gdbpy_initialize_new_inferior_event () < 0
+ || gdbpy_initialize_inferior_deleted_event () < 0
+ || gdbpy_initialize_new_thread_event () < 0
|| gdbpy_initialize_arch () < 0
|| gdbpy_initialize_xmethods () < 0
|| gdbpy_initialize_unwind () < 0)
+2017-09-11 Tom Tromey <tom@tromey.com>
+
+ * gdb.python/py-infthread.exp: Add tests for new_thread event.
+ * gdb.python/py-inferior.exp: Add tests for new inferior events.
+
2017-09-08 Christoph Weinmann <christoph.t.weinmann@intel.com>
* gdb.fortran/printing-types.exp: New file.
gdb_test "python print (inf_list\[0\].is_valid())" "True" \
"check inferior validity 1"
+ gdb_py_test_multiple "install new inferior event handler" \
+ "python" "" \
+ "my_inferior_count = 1" "" \
+ "def new_inf_handler(evt):" "" \
+ " global my_inferior_count" "" \
+ " if evt.inferior is not None:" "" \
+ " my_inferior_count = my_inferior_count + 1" "" \
+ "gdb.events.new_inferior.connect(new_inf_handler)" "" \
+ "end" ""
+ gdb_py_test_multiple "install inferior deleted event handler" \
+ "python" "" \
+ "def del_inf_handler(evt):" "" \
+ " global my_inferior_count" "" \
+ " if evt.inferior is not None:" "" \
+ " my_inferior_count = my_inferior_count - 1" "" \
+ "gdb.events.inferior_deleted.connect(del_inf_handler)" "" \
+ "end" ""
+
gdb_test "add-inferior" "Added inferior 2.*" "add empty inferior 2"
gdb_py_test_silent_cmd "python inf_list = gdb.inferiors()" "get new list" 1
gdb_test "python print (len(inf_list))" "2" "get inferior list length 2"
gdb_test "python print (inf_list\[0\].is_valid())" "True" \
"check inferior validity 2"
+ gdb_test "python print (my_inferior_count)" "2" \
+ "test new-inferior event handler"
+
gdb_test "python print (inf_list\[1\].is_valid())" "True" \
"check inferior validity 3"
gdb_test "python print (inf_list\[1\].is_valid())" "False" \
"check inferior validity 5"
+
+ gdb_test "python print (my_inferior_count)" "1" \
+ "test inferior-deleted event handler"
}
# Test gdb.selected_inferior()
# Skip all tests if Python scripting is not enabled.
if { [skip_python_tests] } { continue }
+gdb_py_test_multiple "install new_thread event handler" \
+ "python" "" \
+ "seen_a_thread = False" "" \
+ "def thread_handler(evt):" "" \
+ " if evt.inferior_thread is not None:" "" \
+ " global seen_a_thread" "" \
+ " seen_a_thread = True" "" \
+ "gdb.events.new_thread.connect(thread_handler)" "" \
+ "end" ""
+
# The following tests require execution.
if ![runto_main] then {
return 0
}
+gdb_test "python print(seen_a_thread)" "True"
+
# Test basic gdb.Inferior attributes and methods.
gdb_py_test_silent_cmd "python t0 = gdb.selected_thread ()" "test gdb.selected_thread" 1