1c50c785cSJohn Marino /* Python interface to inferior threads.
2c50c785cSJohn Marino
3*ef5ccd6cSJohn Marino Copyright (C) 2009-2013 Free Software Foundation, Inc.
4c50c785cSJohn Marino
5c50c785cSJohn Marino This file is part of GDB.
6c50c785cSJohn Marino
7c50c785cSJohn Marino This program is free software; you can redistribute it and/or modify
8c50c785cSJohn Marino it under the terms of the GNU General Public License as published by
9c50c785cSJohn Marino the Free Software Foundation; either version 3 of the License, or
10c50c785cSJohn Marino (at your option) any later version.
11c50c785cSJohn Marino
12c50c785cSJohn Marino This program is distributed in the hope that it will be useful,
13c50c785cSJohn Marino but WITHOUT ANY WARRANTY; without even the implied warranty of
14c50c785cSJohn Marino MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15c50c785cSJohn Marino GNU General Public License for more details.
16c50c785cSJohn Marino
17c50c785cSJohn Marino You should have received a copy of the GNU General Public License
18c50c785cSJohn Marino along with this program. If not, see <http://www.gnu.org/licenses/>. */
19c50c785cSJohn Marino
20c50c785cSJohn Marino #include "defs.h"
21c50c785cSJohn Marino #include "exceptions.h"
22c50c785cSJohn Marino #include "gdbthread.h"
23c50c785cSJohn Marino #include "inferior.h"
24c50c785cSJohn Marino #include "python-internal.h"
25c50c785cSJohn Marino
26c50c785cSJohn Marino static PyTypeObject thread_object_type;
27c50c785cSJohn Marino
28c50c785cSJohn Marino /* Require that INFERIOR be a valid inferior ID. */
29c50c785cSJohn Marino #define THPY_REQUIRE_VALID(Thread) \
30c50c785cSJohn Marino do { \
31c50c785cSJohn Marino if (!Thread->thread) \
32c50c785cSJohn Marino { \
33c50c785cSJohn Marino PyErr_SetString (PyExc_RuntimeError, \
34c50c785cSJohn Marino _("Thread no longer exists.")); \
35c50c785cSJohn Marino return NULL; \
36c50c785cSJohn Marino } \
37c50c785cSJohn Marino } while (0)
38c50c785cSJohn Marino
39c50c785cSJohn Marino
40c50c785cSJohn Marino
41c50c785cSJohn Marino thread_object *
create_thread_object(struct thread_info * tp)42c50c785cSJohn Marino create_thread_object (struct thread_info *tp)
43c50c785cSJohn Marino {
44c50c785cSJohn Marino thread_object *thread_obj;
45c50c785cSJohn Marino
46c50c785cSJohn Marino thread_obj = PyObject_New (thread_object, &thread_object_type);
47c50c785cSJohn Marino if (!thread_obj)
48c50c785cSJohn Marino return NULL;
49c50c785cSJohn Marino
50c50c785cSJohn Marino thread_obj->thread = tp;
51c50c785cSJohn Marino thread_obj->inf_obj = find_inferior_object (PIDGET (tp->ptid));
52c50c785cSJohn Marino
53c50c785cSJohn Marino return thread_obj;
54c50c785cSJohn Marino }
55c50c785cSJohn Marino
56c50c785cSJohn Marino
57c50c785cSJohn Marino
58c50c785cSJohn Marino static void
thpy_dealloc(PyObject * self)59c50c785cSJohn Marino thpy_dealloc (PyObject *self)
60c50c785cSJohn Marino {
61c50c785cSJohn Marino Py_DECREF (((thread_object *) self)->inf_obj);
62*ef5ccd6cSJohn Marino Py_TYPE (self)->tp_free (self);
63c50c785cSJohn Marino }
64c50c785cSJohn Marino
65c50c785cSJohn Marino static PyObject *
thpy_get_name(PyObject * self,void * ignore)66c50c785cSJohn Marino thpy_get_name (PyObject *self, void *ignore)
67c50c785cSJohn Marino {
68c50c785cSJohn Marino thread_object *thread_obj = (thread_object *) self;
69c50c785cSJohn Marino char *name;
70c50c785cSJohn Marino
71c50c785cSJohn Marino THPY_REQUIRE_VALID (thread_obj);
72c50c785cSJohn Marino
73c50c785cSJohn Marino name = thread_obj->thread->name;
74c50c785cSJohn Marino if (name == NULL)
75c50c785cSJohn Marino name = target_thread_name (thread_obj->thread);
76c50c785cSJohn Marino
77c50c785cSJohn Marino if (name == NULL)
78c50c785cSJohn Marino Py_RETURN_NONE;
79c50c785cSJohn Marino
80c50c785cSJohn Marino return PyString_FromString (name);
81c50c785cSJohn Marino }
82c50c785cSJohn Marino
83c50c785cSJohn Marino static int
thpy_set_name(PyObject * self,PyObject * newvalue,void * ignore)84c50c785cSJohn Marino thpy_set_name (PyObject *self, PyObject *newvalue, void *ignore)
85c50c785cSJohn Marino {
86c50c785cSJohn Marino thread_object *thread_obj = (thread_object *) self;
87c50c785cSJohn Marino char *name;
88c50c785cSJohn Marino
89c50c785cSJohn Marino if (! thread_obj->thread)
90c50c785cSJohn Marino {
91c50c785cSJohn Marino PyErr_SetString (PyExc_RuntimeError, _("Thread no longer exists."));
92c50c785cSJohn Marino return -1;
93c50c785cSJohn Marino }
94c50c785cSJohn Marino
95c50c785cSJohn Marino if (newvalue == NULL)
96c50c785cSJohn Marino {
97c50c785cSJohn Marino PyErr_SetString (PyExc_TypeError,
98c50c785cSJohn Marino _("Cannot delete `name' attribute."));
99c50c785cSJohn Marino return -1;
100c50c785cSJohn Marino }
101c50c785cSJohn Marino else if (newvalue == Py_None)
102c50c785cSJohn Marino name = NULL;
103c50c785cSJohn Marino else if (! gdbpy_is_string (newvalue))
104c50c785cSJohn Marino {
105c50c785cSJohn Marino PyErr_SetString (PyExc_TypeError,
106c50c785cSJohn Marino _("The value of `name' must be a string."));
107c50c785cSJohn Marino return -1;
108c50c785cSJohn Marino }
109c50c785cSJohn Marino else
110c50c785cSJohn Marino {
111c50c785cSJohn Marino name = python_string_to_host_string (newvalue);
112c50c785cSJohn Marino if (! name)
113c50c785cSJohn Marino return -1;
114c50c785cSJohn Marino }
115c50c785cSJohn Marino
116c50c785cSJohn Marino xfree (thread_obj->thread->name);
117c50c785cSJohn Marino thread_obj->thread->name = name;
118c50c785cSJohn Marino
119c50c785cSJohn Marino return 0;
120c50c785cSJohn Marino }
121c50c785cSJohn Marino
122c50c785cSJohn Marino static PyObject *
thpy_get_num(PyObject * self,void * closure)123c50c785cSJohn Marino thpy_get_num (PyObject *self, void *closure)
124c50c785cSJohn Marino {
125c50c785cSJohn Marino thread_object *thread_obj = (thread_object *) self;
126c50c785cSJohn Marino
127c50c785cSJohn Marino THPY_REQUIRE_VALID (thread_obj);
128c50c785cSJohn Marino
129c50c785cSJohn Marino return PyLong_FromLong (thread_obj->thread->num);
130c50c785cSJohn Marino }
131c50c785cSJohn Marino
132c50c785cSJohn Marino /* Getter for InferiorThread.ptid -> (pid, lwp, tid).
133c50c785cSJohn Marino Returns a tuple with the thread's ptid components. */
134c50c785cSJohn Marino static PyObject *
thpy_get_ptid(PyObject * self,void * closure)135c50c785cSJohn Marino thpy_get_ptid (PyObject *self, void *closure)
136c50c785cSJohn Marino {
137c50c785cSJohn Marino int pid;
138c50c785cSJohn Marino long tid, lwp;
139c50c785cSJohn Marino thread_object *thread_obj = (thread_object *) self;
140c50c785cSJohn Marino PyObject *ret;
141c50c785cSJohn Marino
142c50c785cSJohn Marino THPY_REQUIRE_VALID (thread_obj);
143c50c785cSJohn Marino
144c50c785cSJohn Marino ret = PyTuple_New (3);
145c50c785cSJohn Marino if (!ret)
146c50c785cSJohn Marino return NULL;
147c50c785cSJohn Marino
148c50c785cSJohn Marino pid = ptid_get_pid (thread_obj->thread->ptid);
149c50c785cSJohn Marino lwp = ptid_get_lwp (thread_obj->thread->ptid);
150c50c785cSJohn Marino tid = ptid_get_tid (thread_obj->thread->ptid);
151c50c785cSJohn Marino
152c50c785cSJohn Marino PyTuple_SET_ITEM (ret, 0, PyInt_FromLong (pid));
153c50c785cSJohn Marino PyTuple_SET_ITEM (ret, 1, PyInt_FromLong (lwp));
154c50c785cSJohn Marino PyTuple_SET_ITEM (ret, 2, PyInt_FromLong (tid));
155c50c785cSJohn Marino
156c50c785cSJohn Marino return ret;
157c50c785cSJohn Marino }
158c50c785cSJohn Marino
159c50c785cSJohn Marino /* Implementation of InferiorThread.switch ().
160c50c785cSJohn Marino Makes this the GDB selected thread. */
161c50c785cSJohn Marino static PyObject *
thpy_switch(PyObject * self,PyObject * args)162c50c785cSJohn Marino thpy_switch (PyObject *self, PyObject *args)
163c50c785cSJohn Marino {
164c50c785cSJohn Marino thread_object *thread_obj = (thread_object *) self;
165c50c785cSJohn Marino volatile struct gdb_exception except;
166c50c785cSJohn Marino
167c50c785cSJohn Marino THPY_REQUIRE_VALID (thread_obj);
168c50c785cSJohn Marino
169c50c785cSJohn Marino TRY_CATCH (except, RETURN_MASK_ALL)
170c50c785cSJohn Marino {
171c50c785cSJohn Marino switch_to_thread (thread_obj->thread->ptid);
172c50c785cSJohn Marino }
173c50c785cSJohn Marino GDB_PY_HANDLE_EXCEPTION (except);
174c50c785cSJohn Marino
175c50c785cSJohn Marino Py_RETURN_NONE;
176c50c785cSJohn Marino }
177c50c785cSJohn Marino
178c50c785cSJohn Marino /* Implementation of InferiorThread.is_stopped () -> Boolean.
179c50c785cSJohn Marino Return whether the thread is stopped. */
180c50c785cSJohn Marino static PyObject *
thpy_is_stopped(PyObject * self,PyObject * args)181c50c785cSJohn Marino thpy_is_stopped (PyObject *self, PyObject *args)
182c50c785cSJohn Marino {
183c50c785cSJohn Marino thread_object *thread_obj = (thread_object *) self;
184c50c785cSJohn Marino
185c50c785cSJohn Marino THPY_REQUIRE_VALID (thread_obj);
186c50c785cSJohn Marino
187c50c785cSJohn Marino if (is_stopped (thread_obj->thread->ptid))
188c50c785cSJohn Marino Py_RETURN_TRUE;
189c50c785cSJohn Marino
190c50c785cSJohn Marino Py_RETURN_FALSE;
191c50c785cSJohn Marino }
192c50c785cSJohn Marino
193c50c785cSJohn Marino /* Implementation of InferiorThread.is_running () -> Boolean.
194c50c785cSJohn Marino Return whether the thread is running. */
195c50c785cSJohn Marino static PyObject *
thpy_is_running(PyObject * self,PyObject * args)196c50c785cSJohn Marino thpy_is_running (PyObject *self, PyObject *args)
197c50c785cSJohn Marino {
198c50c785cSJohn Marino thread_object *thread_obj = (thread_object *) self;
199c50c785cSJohn Marino
200c50c785cSJohn Marino THPY_REQUIRE_VALID (thread_obj);
201c50c785cSJohn Marino
202c50c785cSJohn Marino if (is_running (thread_obj->thread->ptid))
203c50c785cSJohn Marino Py_RETURN_TRUE;
204c50c785cSJohn Marino
205c50c785cSJohn Marino Py_RETURN_FALSE;
206c50c785cSJohn Marino }
207c50c785cSJohn Marino
208c50c785cSJohn Marino /* Implementation of InferiorThread.is_exited () -> Boolean.
209c50c785cSJohn Marino Return whether the thread is exited. */
210c50c785cSJohn Marino static PyObject *
thpy_is_exited(PyObject * self,PyObject * args)211c50c785cSJohn Marino thpy_is_exited (PyObject *self, PyObject *args)
212c50c785cSJohn Marino {
213c50c785cSJohn Marino thread_object *thread_obj = (thread_object *) self;
214c50c785cSJohn Marino
215c50c785cSJohn Marino THPY_REQUIRE_VALID (thread_obj);
216c50c785cSJohn Marino
217c50c785cSJohn Marino if (is_exited (thread_obj->thread->ptid))
218c50c785cSJohn Marino Py_RETURN_TRUE;
219c50c785cSJohn Marino
220c50c785cSJohn Marino Py_RETURN_FALSE;
221c50c785cSJohn Marino }
222c50c785cSJohn Marino
223c50c785cSJohn Marino /* Implementation of gdb.InfThread.is_valid (self) -> Boolean.
224c50c785cSJohn Marino Returns True if this inferior Thread object still exists
225c50c785cSJohn Marino in GDB. */
226c50c785cSJohn Marino
227c50c785cSJohn Marino static PyObject *
thpy_is_valid(PyObject * self,PyObject * args)228c50c785cSJohn Marino thpy_is_valid (PyObject *self, PyObject *args)
229c50c785cSJohn Marino {
230c50c785cSJohn Marino thread_object *thread_obj = (thread_object *) self;
231c50c785cSJohn Marino
232c50c785cSJohn Marino if (! thread_obj->thread)
233c50c785cSJohn Marino Py_RETURN_FALSE;
234c50c785cSJohn Marino
235c50c785cSJohn Marino Py_RETURN_TRUE;
236c50c785cSJohn Marino }
237c50c785cSJohn Marino
238c50c785cSJohn Marino /* Implementation of gdb.selected_thread () -> gdb.InferiorThread.
239c50c785cSJohn Marino Returns the selected thread object. */
240c50c785cSJohn Marino PyObject *
gdbpy_selected_thread(PyObject * self,PyObject * args)241c50c785cSJohn Marino gdbpy_selected_thread (PyObject *self, PyObject *args)
242c50c785cSJohn Marino {
243c50c785cSJohn Marino PyObject *thread_obj;
244c50c785cSJohn Marino
245c50c785cSJohn Marino thread_obj = (PyObject *) find_thread_object (inferior_ptid);
246c50c785cSJohn Marino if (thread_obj)
247c50c785cSJohn Marino {
248c50c785cSJohn Marino Py_INCREF (thread_obj);
249c50c785cSJohn Marino return thread_obj;
250c50c785cSJohn Marino }
251c50c785cSJohn Marino
252c50c785cSJohn Marino Py_RETURN_NONE;
253c50c785cSJohn Marino }
254c50c785cSJohn Marino
255c50c785cSJohn Marino
256c50c785cSJohn Marino
257c50c785cSJohn Marino void
gdbpy_initialize_thread(void)258c50c785cSJohn Marino gdbpy_initialize_thread (void)
259c50c785cSJohn Marino {
260c50c785cSJohn Marino if (PyType_Ready (&thread_object_type) < 0)
261c50c785cSJohn Marino return;
262c50c785cSJohn Marino
263c50c785cSJohn Marino Py_INCREF (&thread_object_type);
264c50c785cSJohn Marino PyModule_AddObject (gdb_module, "InferiorThread",
265c50c785cSJohn Marino (PyObject *) &thread_object_type);
266c50c785cSJohn Marino }
267c50c785cSJohn Marino
268c50c785cSJohn Marino
269c50c785cSJohn Marino
270c50c785cSJohn Marino static PyGetSetDef thread_object_getset[] =
271c50c785cSJohn Marino {
272c50c785cSJohn Marino { "name", thpy_get_name, thpy_set_name,
273c50c785cSJohn Marino "The name of the thread, as set by the user or the OS.", NULL },
274c50c785cSJohn Marino { "num", thpy_get_num, NULL, "ID of the thread, as assigned by GDB.", NULL },
275c50c785cSJohn Marino { "ptid", thpy_get_ptid, NULL, "ID of the thread, as assigned by the OS.",
276c50c785cSJohn Marino NULL },
277c50c785cSJohn Marino
278c50c785cSJohn Marino { NULL }
279c50c785cSJohn Marino };
280c50c785cSJohn Marino
281c50c785cSJohn Marino static PyMethodDef thread_object_methods[] =
282c50c785cSJohn Marino {
283c50c785cSJohn Marino { "is_valid", thpy_is_valid, METH_NOARGS,
284c50c785cSJohn Marino "is_valid () -> Boolean.\n\
285c50c785cSJohn Marino Return true if this inferior thread is valid, false if not." },
286c50c785cSJohn Marino { "switch", thpy_switch, METH_NOARGS,
287c50c785cSJohn Marino "switch ()\n\
288c50c785cSJohn Marino Makes this the GDB selected thread." },
289c50c785cSJohn Marino { "is_stopped", thpy_is_stopped, METH_NOARGS,
290c50c785cSJohn Marino "is_stopped () -> Boolean\n\
291c50c785cSJohn Marino Return whether the thread is stopped." },
292c50c785cSJohn Marino { "is_running", thpy_is_running, METH_NOARGS,
293c50c785cSJohn Marino "is_running () -> Boolean\n\
294c50c785cSJohn Marino Return whether the thread is running." },
295c50c785cSJohn Marino { "is_exited", thpy_is_exited, METH_NOARGS,
296c50c785cSJohn Marino "is_exited () -> Boolean\n\
297c50c785cSJohn Marino Return whether the thread is exited." },
298c50c785cSJohn Marino
299c50c785cSJohn Marino { NULL }
300c50c785cSJohn Marino };
301c50c785cSJohn Marino
302c50c785cSJohn Marino static PyTypeObject thread_object_type =
303c50c785cSJohn Marino {
304*ef5ccd6cSJohn Marino PyVarObject_HEAD_INIT (NULL, 0)
305c50c785cSJohn Marino "gdb.InferiorThread", /*tp_name*/
306c50c785cSJohn Marino sizeof (thread_object), /*tp_basicsize*/
307c50c785cSJohn Marino 0, /*tp_itemsize*/
308c50c785cSJohn Marino thpy_dealloc, /*tp_dealloc*/
309c50c785cSJohn Marino 0, /*tp_print*/
310c50c785cSJohn Marino 0, /*tp_getattr*/
311c50c785cSJohn Marino 0, /*tp_setattr*/
312c50c785cSJohn Marino 0, /*tp_compare*/
313c50c785cSJohn Marino 0, /*tp_repr*/
314c50c785cSJohn Marino 0, /*tp_as_number*/
315c50c785cSJohn Marino 0, /*tp_as_sequence*/
316c50c785cSJohn Marino 0, /*tp_as_mapping*/
317c50c785cSJohn Marino 0, /*tp_hash */
318c50c785cSJohn Marino 0, /*tp_call*/
319c50c785cSJohn Marino 0, /*tp_str*/
320c50c785cSJohn Marino 0, /*tp_getattro*/
321c50c785cSJohn Marino 0, /*tp_setattro*/
322c50c785cSJohn Marino 0, /*tp_as_buffer*/
323c50c785cSJohn Marino Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/
324c50c785cSJohn Marino "GDB thread object", /* tp_doc */
325c50c785cSJohn Marino 0, /* tp_traverse */
326c50c785cSJohn Marino 0, /* tp_clear */
327c50c785cSJohn Marino 0, /* tp_richcompare */
328c50c785cSJohn Marino 0, /* tp_weaklistoffset */
329c50c785cSJohn Marino 0, /* tp_iter */
330c50c785cSJohn Marino 0, /* tp_iternext */
331c50c785cSJohn Marino thread_object_methods, /* tp_methods */
332c50c785cSJohn Marino 0, /* tp_members */
333c50c785cSJohn Marino thread_object_getset, /* tp_getset */
334c50c785cSJohn Marino 0, /* tp_base */
335c50c785cSJohn Marino 0, /* tp_dict */
336c50c785cSJohn Marino 0, /* tp_descr_get */
337c50c785cSJohn Marino 0, /* tp_descr_set */
338c50c785cSJohn Marino 0, /* tp_dictoffset */
339c50c785cSJohn Marino 0, /* tp_init */
340c50c785cSJohn Marino 0 /* tp_alloc */
341c50c785cSJohn Marino };
342